summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-10-03 01:28:04 +0000
committerPaul Phillips <paulp@improving.org>2011-10-03 01:28:04 +0000
commitbeadafa2d83a539dae8f969b9789f896346484ec (patch)
tree90c69a49397cdb59120d59307b843c54c8f68908 /src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
parent55109d0d253c7e89660f1b61d17408648c0c53a4 (diff)
downloadscala-beadafa2d83a539dae8f969b9789f896346484ec.tar.gz
scala-beadafa2d83a539dae8f969b9789f896346484ec.tar.bz2
scala-beadafa2d83a539dae8f969b9789f896346484ec.zip
Selective dealiasing when printing errors.
*** Important note for busy commit log skimmers *** Symbol method "fullName" has been trying to serve the dual role of "how to print a symbol" and "how to find a class file." It cannot serve both these roles simultaneously, primarily because of package objects but other little things as well. Since in the majority of situations we want the one which corresponds to the idealized scala world, not the grubby bytecode, I went with that for fullName. When you require the path to a class (e.g. you are calling Class.forName) you should use javaClassName. package foo { package object bar { class Bippy } } If sym is Bippy's symbol, then sym.fullName == foo.bar.Bippy sym.javaClassName == foo.bar.package.Bippy *** End important note *** There are many situations where we (until now) forewent revealing everything we knew about a type mismatch. For instance, this isn't very helpful of scalac (at least in those more common cases where you didn't define type X on the previous repl line.) scala> type X = Int defined type alias X scala> def f(x: X): Byte = x <console>:8: error: type mismatch; found : X required: Byte def f(x: X): Byte = x ^ Now it says: found : X (which expands to) Int required: Byte def f(x: X): Byte = x ^ In addition I rearchitected a number of methods involving: - finding a symbol's owner - calculating a symbol's name - determining whether to print a prefix No review.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala42
1 files changed, 30 insertions, 12 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 6e0e78e8e2..6c735a2d44 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -82,6 +82,17 @@ trait TypeDiagnostics {
def posPrecedes(p1: Position, p2: Position) = p1.isDefined && p2.isDefined && p1.line < p2.line
def linePrecedes(t1: Tree, t2: Tree) = posPrecedes(t1.pos, t2.pos)
+ private object DealiasedType extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ // Avoid "explaining" that String is really java.lang.String,
+ // while still dealiasing types from non-default namespaces.
+ case TypeRef(pre, sym, args) if sym.isAliasType && !sym.isInDefaultNamespace =>
+ mapOver(tp.dealias)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
def notAMemberMessage(pos: Position, qual: Tree, name: Name) = {
val owner = qual.tpe.typeSymbol
val target = qual.tpe.widen
@@ -212,12 +223,17 @@ 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
- )
+ def explainAlias(tp: Type) = {
+ // Don't automatically normalize standard aliases; they still will be
+ // expanded if necessary to disambiguate simple identifiers.
+ if ((tp eq tp.normalize) || tp.typeSymbolDirect.isInDefaultNamespace) ""
+ else {
+ // A sanity check against expansion being identical to original.
+ val s = "" + DealiasedType(tp)
+ if (s == "" + tp) ""
+ else "\n (which expands to) " + s
+ }
+ }
/** Look through the base types of the found type for any which
* might have been valid subtypes if given conformant type arguments.
@@ -292,7 +308,6 @@ trait TypeDiagnostics {
}
"" // no elaborable variance situation found
}
-
def foundReqMsg(found: Type, req: Type): String = (
withDisambiguation(Nil, found, req)(
";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) +
@@ -309,8 +324,11 @@ trait TypeDiagnostics {
def modifyName(f: String => String) =
sym.name = newTypeName(f(sym.name.toString))
- def scalaQualify() = {
- val intersect = Set(trueOwner, aliasOwner) intersect Set(ScalaPackageClass, PredefModuleClass)
+ /** Prepend java.lang, scala., or Predef. if this type originated
+ * in one of those.
+ */
+ def qualifyDefaultNamespaces() = {
+ val intersect = Set(trueOwner, aliasOwner) intersect UnqualifiedOwners
if (intersect.nonEmpty) preQualify()
}
@@ -320,8 +338,8 @@ trait TypeDiagnostics {
def typeQualify() = if (sym.isTypeParameterOrSkolem) postQualify()
def nameQualify() = if (trueOwner.isPackageClass) preQualify() else postQualify()
- def trueOwner = tp.typeSymbol.owner.skipPackageObject
- def aliasOwner = tp.typeSymbolDirect.owner.skipPackageObject
+ def trueOwner = tp.typeSymbol.effectiveOwner
+ def aliasOwner = tp.typeSymbolDirect.effectiveOwner
def sym_==(other: TypeDiag) = tp.typeSymbol == other.tp.typeSymbol
def owner_==(other: TypeDiag) = trueOwner == other.trueOwner
@@ -385,7 +403,7 @@ trait TypeDiagnostics {
// scala package or predef, qualify with scala so it is not confusing why
// e.g. java.util.Iterator and Iterator are different types.
if (td1 name_== td2)
- tds foreach (_.scalaQualify())
+ tds foreach (_.qualifyDefaultNamespaces())
// If they still print identically:
// a) If they are type parameters with different owners, append (in <owner>)