summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-04-28 16:23:45 +0000
committerPaul Phillips <paulp@improving.org>2011-04-28 16:23:45 +0000
commit199ec3c10fe7d2b2029ea8ae6a19240b46181435 (patch)
treef0e7b14111510f19bf89874d3073adf767d16054 /src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
parent9a9f73b80261415e08eb782333470bbb84863894 (diff)
downloadscala-199ec3c10fe7d2b2029ea8ae6a19240b46181435.tar.gz
scala-199ec3c10fe7d2b2029ea8ae6a19240b46181435.tar.bz2
scala-199ec3c10fe7d2b2029ea8ae6a19240b46181435.zip
Improved the error message for another of the m...
Improved the error message for another of the most common situations I hear about in newbieland. It could be taken further. If compilation fails due to an unimplemented abstract method, and there is a concrete method of the same name and arity, it will do a pairwise analysis of the parameters and attempt to further explain where you went off the beam if it feels it can do so sensibly. Such as in the test case: % scalac S.scala S.scala:1: error: class S needs to be abstract, since method g in class J of type (y: Int,z: java.util.List)Int is not defined (Note that java.util.List does not match java.util.List[String]. To implement a raw type, use java.util.List[_]) class S extends J { ^ one error found No review.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/RefChecks.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 3eb5107870..a23e5d704e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -507,6 +507,48 @@ abstract class RefChecks extends InfoTransform {
else analyzer.varNotice(member)
)
}
+ else if (underlying.isMethod) {
+ // If there is a concrete method whose name matches the unimplemented
+ // abstract method, and a cursory examination of the difference reveals
+ // something obvious to us, let's make it more obvious to them.
+ val abstractParams = underlying.tpe.paramTypes
+ val matchingName = clazz.tpe.nonPrivateMembersAdmitting(VBRIDGE)
+ val matchingArity = matchingName filter { m =>
+ !m.isDeferred &&
+ (m.name == underlying.name) &&
+ (m.tpe.paramTypes.size == underlying.tpe.paramTypes.size) &&
+ (m.tpe.typeParams.size == underlying.tpe.typeParams.size)
+ }
+
+ matchingArity match {
+ // So far so good: only one candidate method
+ case concrete :: Nil =>
+ val mismatches = abstractParams zip concrete.tpe.paramTypes filterNot { case (x, y) => x =:= y }
+ mismatches match {
+ // Only one mismatched parameter: say something useful.
+ case (pa, pc) :: Nil =>
+ val addendum =
+ if (pa.typeSymbol == pc.typeSymbol) {
+ // 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)
+ ". 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 ""
+
+ undefined("\n(Note that %s does not match %s%s)".format(pa, pc, addendum))
+ case xs =>
+ undefined("")
+ }
+ case _ =>
+ undefined("")
+ }
+ }
else undefined("")
}