summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-08-06 21:53:17 +0000
committerPaul Phillips <paulp@improving.org>2011-08-06 21:53:17 +0000
commit05382e2351e1ec6ebfbb50c4df12a2b1410a0b80 (patch)
tree4112795a3f5fa89fa47408a20526b88d57599c34 /src/compiler
parent990fa046e6bbe95d5def208b38fead77d2437f9f (diff)
downloadscala-05382e2351e1ec6ebfbb50c4df12a2b1410a0b80.tar.gz
scala-05382e2351e1ec6ebfbb50c4df12a2b1410a0b80.tar.bz2
scala-05382e2351e1ec6ebfbb50c4df12a2b1410a0b80.zip
Improved structural type error messages, and ot...
Improved structural type error messages, and other error message related boosts. Closes SI-4877, review by odersky.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala25
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala19
2 files changed, 37 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 495594da5e..b70f20ea89 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -229,7 +229,30 @@ trait Infer {
}
def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = {
- typeError(tree.pos, found, req)
+ // If the expected type is a refinement type, and the found type is a refinement or an anon
+ // class, we can greatly improve the error message by retyping the tree to recover the actual
+ // members present, then display along with the expected members. This is done here because
+ // this is the last point where we still have access to the original tree, rather than just
+ // the found/req types.
+ val foundType: Type = req.normalize match {
+ case RefinedType(parents, decls) if !decls.isEmpty && found.typeSymbol.isAnonOrRefinementClass =>
+ val retyped = typer typed (tree.duplicate setType null)
+ val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic)
+
+ if (foundDecls.isEmpty) found
+ else {
+ // The members arrive marked private, presumably because there was no
+ // expected type and so they're considered members of an anon class.
+ foundDecls foreach (_ resetFlag (PRIVATE | PROTECTED))
+ // TODO: if any of the found parents match up with required parents after normalization,
+ // print the error so that they match. The major beneficiary there would be
+ // java.lang.Object vs. AnyRef.
+ refinedType(found.parents, found.typeSymbol.owner, foundDecls, tree.pos)
+ }
+ case _ =>
+ found
+ }
+ typeError(tree.pos, foundType, req)
setError(tree)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 2c424d17d7..6e0e78e8e2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -212,6 +212,13 @@ trait TypeDiagnostics {
else if (sym.variance == -1) "contravariant"
else "invariant"
+ // I think this should definitely be on by default, but I need to
+ // play with it a bit longer. For now it's behind -Xlint.
+ def explainAlias(tp: Type) = (
+ if (!settings.lint.value || (tp eq tp.normalize)) ""
+ else " (which expands to)\n " + tp.normalize
+ )
+
/** Look through the base types of the found type for any which
* might have been valid subtypes if given conformant type arguments.
* Examine those for situations where the type error would have been
@@ -286,12 +293,12 @@ trait TypeDiagnostics {
"" // no elaborable variance situation found
}
- def foundReqMsg(found: Type, req: Type): String = {
- (withDisambiguation(List(), found, req) {
- ";\n found : " + found.toLongString + existentialContext(found) +
- "\n required: " + req + existentialContext(req)
- }) + explainVariance(found, req)
- }
+ def foundReqMsg(found: Type, req: Type): String = (
+ withDisambiguation(Nil, found, req)(
+ ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) +
+ "\n required: " + req + existentialContext(req) + explainAlias(req)
+ ) + explainVariance(found, req)
+ )
case class TypeDiag(tp: Type, sym: Symbol) extends Ordered[TypeDiag] {
// save the name because it will be mutated until it has been