Skip to content

Commit

Permalink
Selective dealiasing when printing errors.
Browse files Browse the repository at this point in the history
*** 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.
  • Loading branch information
paulp committed Oct 3, 2011
1 parent 55109d0 commit beadafa
Show file tree
Hide file tree
Showing 70 changed files with 366 additions and 321 deletions.
23 changes: 16 additions & 7 deletions src/compiler/scala/reflect/internal/Definitions.scala
Expand Up @@ -142,12 +142,13 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val EmptyPackage = RootClass.newPackage(NoPosition, nme.EMPTY_PACKAGE_NAME).setFlag(FINAL)
lazy val EmptyPackageClass = EmptyPackage.moduleClass

lazy val JavaLangPackage = getModule(sn.JavaLang)
lazy val ScalaPackage = getModule("scala")
lazy val ScalaPackageClass = ScalaPackage.tpe.typeSymbol
lazy val JavaLangPackage = getModule(sn.JavaLang)
lazy val JavaLangPackageClass = JavaLangPackage.moduleClass
lazy val ScalaPackage = getModule(nme.scala_)
lazy val ScalaPackageClass = ScalaPackage.moduleClass

lazy val RuntimePackage = getModule("scala.runtime")
lazy val RuntimePackageClass = RuntimePackage.tpe.typeSymbol
lazy val RuntimePackageClass = RuntimePackage.moduleClass

// convenient one-argument parameter lists
lazy val anyparam = List(AnyClass.typeConstructor)
Expand Down Expand Up @@ -221,7 +222,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val BridgeClass = getClass("scala.annotation.bridge")

// fundamental reference classes
lazy val ScalaObjectClass = getClass("scala.ScalaObject")
lazy val ScalaObjectClass = getMember(ScalaPackageClass, tpnme.ScalaObject)
lazy val PartialFunctionClass = getClass("scala.PartialFunction")
lazy val SymbolClass = getClass("scala.Symbol")
lazy val StringClass = getClass(sn.String)
Expand All @@ -233,9 +234,17 @@ trait Definitions extends reflect.api.StandardDefinitions {
// fundamental modules
lazy val SysPackage = getPackageObject("scala.sys")
def Sys_error = getMember(SysPackage, nme.error)

// Modules whose members are in the default namespace
lazy val UnqualifiedModules = List(PredefModule, ScalaPackage, JavaLangPackage)
// Those modules and their module classes
lazy val UnqualifiedOwners = UnqualifiedModules.toSet ++ UnqualifiedModules.map(_.moduleClass)

lazy val PredefModule: Symbol = getModule("scala.Predef")
lazy val PredefModuleClass = PredefModule.tpe.typeSymbol
def Predef_AnyRef = getMember(PredefModule, "AnyRef") // used by the specialization annotation
lazy val PredefModuleClass = PredefModule.moduleClass
// Note: this is not the type alias AnyRef, it's a val defined in Predef
// used by the @specialize annotation.
def Predef_AnyRef = getMember(PredefModule, tpnme.AnyRef.toTermName)
def Predef_classOf = getMember(PredefModule, nme.classOf)
def Predef_identity = getMember(PredefModule, nme.identity)
def Predef_conforms = getMember(PredefModule, nme.conforms)
Expand Down
86 changes: 48 additions & 38 deletions src/compiler/scala/reflect/internal/Symbols.scala
Expand Up @@ -395,34 +395,40 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
final def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass

final def isPackageObject = isModule && name == nme.PACKAGEkw && owner.isPackageClass
final def isPackageObjectClass = isModuleClass && name.toTermName == nme.PACKAGEkw && owner.isPackageClass
final def definedInPackage = owner.isPackageClass || owner.isPackageObjectClass
def isPackageObjectOrClass = (name.toTermName == nme.PACKAGEkw) && owner.isPackageClass
final def isPackageObject = isModule && isPackageObjectOrClass
final def isPackageObjectClass = isModuleClass && isPackageObjectOrClass
final def isDefinedInPackage = effectiveOwner.isPackageClass
final def isJavaInterface = isJavaDefined && isTrait
final def needsFlatClasses: Boolean = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass

// not printed as prefixes
final def isPredefModule = this == PredefModule
final def isScalaPackage = (this == ScalaPackage) || (isPackageObject && owner == ScalaPackageClass)
final def isScalaPackageClass = skipPackageObject == ScalaPackageClass
def inDefaultNamespace = owner.isPredefModule || owner.isScalaPackageClass
// In java.lang, Predef, or scala package/package object
def isInDefaultNamespace = UnqualifiedOwners(effectiveOwner)

/** If this is a package object or package object class, its owner: otherwise this.
*/
final def skipPackageObject: Symbol = if (isPackageObjectClass) owner else this

/** The owner, skipping package objects.
*/
def effectiveOwner = owner.skipPackageObject

/** If this is a constructor, its owner: otherwise this.
*/
final def skipConstructor: Symbol = if (isConstructor) owner else this

/** Conditions where we omit the prefix when printing a symbol, to avoid
* unpleasantries like Predef.String, $iw.$iw.Foo and <empty>.Bippy.
*/
final def printWithoutPrefix = !settings.debug.value && (
isScalaPackageClass || isPredefModule || isEffectiveRoot || isAnonOrRefinementClass ||
nme.isReplWrapperName(name) // not isInterpreterWrapper due to nesting
final def isOmittablePrefix = !settings.debug.value && (
UnqualifiedOwners(skipPackageObject)
|| isEmptyPrefix
)
def isEmptyPrefix = (
isEffectiveRoot // has no prefix for real, <empty> or <root>
|| isAnonOrRefinementClass // has uninteresting <anon> or <refinement> prefix
|| nme.isReplWrapperName(name) // has ugly $iw. prefix (doesn't call isInterpreterWrapper due to nesting)
)

def isFBounded = info.baseTypeSeq exists (_ contains this)

/** Is symbol a monomorphic type?
Expand Down Expand Up @@ -723,7 +729,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

/** The decoded name of the symbol, e.g. `==` instead of `\$eq\$eq`.
*/
def decodedName: String = stripLocalSuffix(NameTransformer.decode(encodedName))
def decodedName: String = stripNameString(NameTransformer.decode(encodedName))

def moduleSuffix: String = (
if (hasModuleFlag && !isMethod && !isImplClass && !isJavaDefined) nme.MODULE_SUFFIX_STRING
Expand All @@ -732,22 +738,32 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

/** These should be moved somewhere like JavaPlatform.
*/
def javaSimpleName = stripLocalSuffix("" + simpleName) + moduleSuffix
def javaBinaryName = fullName('/') + moduleSuffix
def javaClassName = fullName('.') + moduleSuffix
def javaSimpleName = ("" + simpleName).trim + moduleSuffix
def javaBinaryName = fullNameInternal('/') + moduleSuffix
def javaClassName = fullNameInternal('.') + moduleSuffix

/** The encoded full path name of this symbol, where outer names and inner names
* are separated by `separator` characters.
* Never translates expansions of operators back to operator symbol.
* Never adds id.
* Drops package objects.
*/
final def fullName(separator: Char): String = stripNameString(fullNameInternal(separator))

/** Doesn't drop package objects, for those situations (e.g. classloading)
* where the true path is needed.
*/
final def fullName(separator: Char): String = stripLocalSuffix {
private def fullNameInternal(separator: Char): String = (
if (isRoot || isRootPackage || this == NoSymbol) this.toString
else if (owner.isEffectiveRoot) encodedName
else owner.enclClass.fullName(separator) + separator + encodedName
}
else effectiveOwner.enclClass.fullName(separator) + separator + encodedName
)

private def stripLocalSuffix(s: String) = s stripSuffix nme.LOCAL_SUFFIX_STRING
/** Strip package objects and any local suffix.
*/
private def stripNameString(s: String) =
if (settings.debug.value) s
else s.replaceAllLiterally(".package", "").trim

/** The encoded full path name of this symbol, where outer names and inner names
* are separated by periods.
Expand Down Expand Up @@ -1358,11 +1374,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

/** The package containing this symbol, or NoSymbol if there
* is not one. */
def enclosingPackage: Symbol = {
val packSym = enclosingPackageClass
if (packSym != NoSymbol) packSym.companionModule
else packSym
}
def enclosingPackage: Symbol = enclosingPackageClass.companionModule

/** Return the original enclosing method of this symbol. It should return
* the same thing as enclMethod when called before lambda lift,
Expand Down Expand Up @@ -1420,8 +1432,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Is this symbol defined in the same scope and compilation unit as `that` symbol? */
def isCoDefinedWith(that: Symbol) = (
(this.rawInfo ne NoType) &&
(this.owner == that.owner) && {
!this.owner.isPackageClass ||
(this.effectiveOwner == that.effectiveOwner) && {
!this.effectiveOwner.isPackageClass ||
(this.sourceFile eq null) ||
(that.sourceFile eq null) ||
(this.sourceFile == that.sourceFile) || {
Expand Down Expand Up @@ -1784,11 +1796,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* to the name of the owner.
*/
def hasMeaninglessName = (
isSetterParameter // x$1
|| isClassConstructor // this
|| isPackageObject // package
|| isPackageObjectClass // package$
|| isRefinementClass // <refinement>
isSetterParameter // x$1
|| isClassConstructor // this
|| isPackageObjectOrClass // package
|| isRefinementClass // <refinement>
)

/** String representation of symbol's simple name.
Expand All @@ -1812,9 +1823,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** String representation of location.
*/
def ownsString = {
val owns = owner.skipPackageObject
if (owns.isClass && !owns.printWithoutPrefix && !isScalaPackageClass) "" + owns
else ""
val owns = effectiveOwner
if (owns.isClass && !owns.isEmptyPrefix) "" + owns else ""
}

/** String representation of location, plus a preposition. Doesn't do much,
Expand Down Expand Up @@ -1963,7 +1973,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

protected def doCookJavaRawInfo() {
def cook(sym: Symbol) {
require(sym hasFlag JAVA)
require(sym.isJavaDefined, sym)
// @M: I think this is more desirable, but Martin prefers to leave raw-types as-is as much as possible
// object rawToExistentialInJava extends TypeMap {
// def apply(tp: Type): Type = tp match {
Expand All @@ -1985,9 +1995,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

if (isJavaDefined)
cook(this)
else if (hasFlag(OVERLOADED))
else if (isOverloaded)
for (sym2 <- alternatives)
if (sym2 hasFlag JAVA)
if (sym2.isJavaDefined)
cook(sym2)
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/compiler/scala/reflect/internal/Types.scala
Expand Up @@ -1157,7 +1157,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def prefixString =
if (settings.debug.value) sym.nameString + ".this."
else if (sym.isAnonOrRefinementClass) "this."
else if (sym.printWithoutPrefix) ""
else if (sym.isOmittablePrefix) ""
else if (sym.isModuleClass) sym.fullName + "."
else sym.nameString + ".this."
override def safeToString: String =
Expand Down Expand Up @@ -1220,8 +1220,9 @@ trait Types extends api.Types { self: SymbolTable =>

override def termSymbol = sym
override def prefix: Type = pre
override def prefixString: String =
if ((sym.isEmptyPackage || sym.isInterpreterWrapper || sym.isPredefModule || sym.isScalaPackage) && !settings.debug.value) ""
override def prefixString =
if (sym.isPackageObjectOrClass) pre.prefixString
else if (sym.isOmittablePrefix) ""
else pre.prefixString + sym.nameString + "."
override def kind = "SingleType"
}
Expand Down Expand Up @@ -2050,8 +2051,10 @@ A type's typeSymbol should never be inspected directly.
override def prefixString = "" + (
if (settings.debug.value)
super.prefixString
else if (sym.printWithoutPrefix)
else if (sym.isOmittablePrefix)
""
else if (sym.isPackageObjectOrClass)
sym.owner.fullName + "."
else if (sym.isPackageClass)
sym.fullName + "."
else if (isStable && nme.isSingletonName(sym.name))
Expand Down Expand Up @@ -4080,7 +4083,7 @@ A type's typeSymbol should never be inspected directly.
def corresponds(sym1: Symbol, sym2: Symbol): Boolean =
sym1.name == sym2.name && (sym1.isPackageClass || corresponds(sym1.owner, sym2.owner))
if (!corresponds(sym.owner, rebind0.owner)) {
debuglog("ADAPT1 pre = "+pre+", sym = "+sym+sym.locationString+", rebind = "+rebind0+rebind0.locationString)
debuglog("ADAPT1 pre = "+pre+", sym = "+sym.fullLocationString+", rebind = "+rebind0.fullLocationString)
val bcs = pre.baseClasses.dropWhile(bc => !corresponds(bc, sym.owner));
if (bcs.isEmpty)
assert(pre.typeSymbol.isRefinementClass, pre) // if pre is a refinementclass it might be a structural type => OK to leave it in.
Expand All @@ -4089,11 +4092,8 @@ A type's typeSymbol should never be inspected directly.
debuglog(
"ADAPT2 pre = " + pre +
", bcs.head = " + bcs.head +
", sym = " + sym+sym.locationString +
", rebind = " + rebind0 + (
if (rebind0 == NoSymbol) ""
else rebind0.locationString
)
", sym = " + sym.fullLocationString +
", rebind = " + rebind0.fullLocationString
)
}
val rebind = rebind0.suchThat(sym => sym.isType || sym.isStable)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/runtime/Loaders.scala
Expand Up @@ -35,7 +35,7 @@ trait Loaders { self: SymbolTable =>
assert(sym == clazz || sym == module || sym == module.moduleClass)
// try {
atPhaseNotLaterThan(picklerPhase) {
unpickleClass(clazz, module, javaClass(clazz.fullName))
unpickleClass(clazz, module, javaClass(clazz.javaClassName))
// } catch {
// case ex: ClassNotFoundException => makePackage()
// case ex: NoClassDefFoundError => makePackage()
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/runtime/ScalaToJava.scala
Expand Up @@ -43,7 +43,7 @@ trait ScalaToJava extends ConversionUtil { self: SymbolTable =>
else if (clazz == ArrayClass)
noClass
else if (clazz.owner.isPackageClass)
javaClass(clazz.fullName)
javaClass(clazz.javaClassName)
else if (clazz.owner.isClass)
classToJava(clazz.owner)
.getDeclaredClasses
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
Expand Up @@ -39,7 +39,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
"memberSym " + memberSym + " templateSym " + templateSym + " encls = " +
closestPackage(memberSym) + ", " + closestPackage(templateSym)
)
memberSym.inDefaultNamespace || (closestPackage(memberSym) == closestPackage(templateSym))
memberSym.isOmittablePrefix || (closestPackage(memberSym) == closestPackage(templateSym))
}

private lazy val noSubclassCache = Set(AnyClass, AnyRefClass, ObjectClass, ScalaObjectClass)
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/scala/tools/nsc/typechecker/Implicits.scala
Expand Up @@ -335,8 +335,8 @@ trait Implicits {
pre1: String, pre2: String, trailer: String) =
if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) {
val coreMsg =
pre1+" "+info1.sym+info1.sym.locationString+" of type "+info1.tpe+"\n "+
pre2+" "+info2.sym+info2.sym.locationString+" of type "+info2.tpe+"\n "+
pre1+" "+info1.sym.fullLocationString+" of type "+info1.tpe+"\n "+
pre2+" "+info2.sym.fullLocationString+" of type "+info2.tpe+"\n "+
trailer
error(tree.pos,
if (isView) {
Expand Down Expand Up @@ -408,7 +408,7 @@ trait Implicits {
if (!(pt.isErroneous))
context.unit.error(
tree.pos, "diverging implicit expansion for type "+pt+"\nstarting with "+
info.sym+info.sym.locationString)
info.sym.fullLocationString)
SearchFailure
} else {
throw DivergentImplicit
Expand Down Expand Up @@ -545,7 +545,7 @@ trait Implicits {
SearchFailure
else if (!hasMatchingSymbol(itree1))
fail("candidate implicit %s is shadowed by other implicit %s".format(
info.sym + info.sym.locationString, itree1.symbol + itree1.symbol.locationString))
info.sym.fullLocationString, itree1.symbol.fullLocationString))
else {
val tvars = undetParams map freshVar

Expand Down
Expand Up @@ -403,7 +403,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
val isCandidate = (
sym.isProtected
&& sym.isJavaDefined
&& !sym.definedInPackage
&& !sym.isDefinedInPackage
&& !accessibleThroughSubclassing
&& (sym.owner.enclosingPackageClass != currentOwner.enclosingPackageClass)
&& (sym.owner.enclosingPackageClass == packageAccessBoundry(sym))
Expand Down

0 comments on commit beadafa

Please sign in to comment.