Skip to content

Commit

Permalink
Pushed Symbol/Type creation partitioning further.
Browse files Browse the repository at this point in the history
Yet more funnelling of immutable creation-time known information
into the identities of symbols and types.
  • Loading branch information
paulp committed Apr 1, 2012
1 parent 17356bf commit f7535f7
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 88 deletions.
66 changes: 49 additions & 17 deletions src/compiler/scala/reflect/internal/Definitions.scala
Expand Up @@ -138,26 +138,47 @@ trait Definitions extends reflect.api.StandardDefinitions {
// symbols related to packages
var emptypackagescope: Scope = null //debug

// This is the package _root_. The actual root cannot be referenced at
// the source level, but _root_ is essentially a function () => <root>.
lazy val RootPackage: Symbol = {
val rp = (
NoSymbol.newValue(nme.ROOTPKG, NoPosition, FINAL | MODULE | PACKAGE | JAVA)
setInfo NullaryMethodType(RootClass.tpe)
)
RootClass.sourceModule = rp
rp
sealed trait WellKnownSymbol extends Symbol {
this initFlags TopLevelCreationFlags
}
// Features common to RootClass and RootPackage, the roots of all
// type and term symbols respectively.
sealed trait RootSymbol extends WellKnownSymbol {
final override def isRootSymbol = true
}
// This is the package _root_. The actual root cannot be referenced at
// the source level, but _root_ is essentially a function => <root>.
final object RootPackage extends ModuleSymbol(NoSymbol, NoPosition, nme.ROOTPKG) with RootSymbol {
this setInfo NullaryMethodType(RootClass.tpe)
RootClass.sourceModule = this

// This is the actual root of everything, including the package _root_.
lazy val RootClass: ModuleClassSymbol = (
NoSymbol.newModuleClassSymbol(tpnme.ROOT, NoPosition, FINAL | MODULE | PACKAGE | JAVA)
setInfo rootLoader
)
override def isRootPackage = true
}
// This is <root>, the actual root of everything except the package _root_.
// <root> and _root_ (RootPackage and RootClass) should be the only "well known"
// symbols owned by NoSymbol. All owner chains should go through RootClass,
// although it is probable that some symbols are created as direct children
// of NoSymbol to ensure they will not be stumbled upon. (We should designate
// a better encapsulated place for that.)
final object RootClass extends ModuleClassSymbol(NoSymbol, NoPosition, tpnme.ROOT) with RootSymbol {
this setInfo rootLoader

override def isRoot = true
override def isEffectiveRoot = true
override def isStatic = true
override def isNestedClass = false
override def ownerOfNewSymbols = EmptyPackageClass
}
// The empty package, which holds all top level types without given packages.
lazy val EmptyPackage = RootClass.newPackage(nme.EMPTY_PACKAGE_NAME, NoPosition, FINAL)
lazy val EmptyPackageClass = EmptyPackage.moduleClass

final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEmptyPackage = true
}
final object EmptyPackageClass extends ModuleClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEffectiveRoot = true
override def isEmptyPackageClass = true
}
// It becomes tricky to create dedicated objects for other symbols because
// of initialization order issues.
lazy val JavaLangPackage = getModule(sn.JavaLang)
lazy val JavaLangPackageClass = JavaLangPackage.moduleClass
lazy val ScalaPackage = getModule(nme.scala_)
Expand Down Expand Up @@ -542,6 +563,12 @@ trait Definitions extends reflect.api.StandardDefinitions {

// Checks whether the given type is true for the given condition,
// or if it is a specialized subtype of a type for which it is true.
//
// Origins notes:
// An issue was introduced with specialization in that the implementation
// of "isTupleType" in Definitions relied upon sym == TupleClass(elems.length).
// This test is untrue for specialized tuples, causing mysterious behavior
// because only some tuples are specialized.
def isPossiblySpecializedType(tp: Type)(cond: Type => Boolean) = {
cond(tp) || (tp match {
case TypeRef(pre, sym, args) if sym hasFlag SPECIALIZED =>
Expand Down Expand Up @@ -1112,9 +1139,14 @@ trait Definitions extends reflect.api.StandardDefinitions {
def init() {
if (isInitialized) return

// Still fiddling with whether it's cleaner to do some of this setup here
// or from constructors. The latter approach tends to invite init order issues.
EmptyPackageClass setInfo ClassInfoType(Nil, newPackageScope(EmptyPackageClass), EmptyPackageClass)
EmptyPackage setInfo EmptyPackageClass.tpe

connectModuleToClass(EmptyPackage, EmptyPackageClass)
connectModuleToClass(RootPackage, RootClass)

RootClass.info.decls enter EmptyPackage
RootClass.info.decls enter RootPackage

Expand Down
32 changes: 19 additions & 13 deletions src/compiler/scala/reflect/internal/Symbols.scala
Expand Up @@ -451,22 +451,30 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isVarargsMethod = isMethod && hasFlag(VARARGS)

/** Package tests */
final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME
final def isEmptyPackageClass = isPackageClass && name == tpnme.EMPTY_PACKAGE_NAME
final def isPackage = isModule && hasFlag(PACKAGE)
final def isPackageClass = isClass && hasFlag(PACKAGE)
final def isRoot = isPackageClass && owner == NoSymbol
final def isRootPackage = isPackage && owner == NoSymbol

/** Overridden in custom objects in Definitions */
def isRoot = false
def isRootPackage = false
def isRootSymbol = false // RootPackage and RootClass. TODO: also NoSymbol.
def isEmptyPackage = false
def isEmptyPackageClass = false

/** Is this symbol an effective root for fullname string?
*/
def isEffectiveRoot = false

/** For RootClass, EmptyPackageClass. For all other symbols, itself.
*/
def ownerOfNewSymbols = this

/** Does this symbol denote a wrapper created by the repl? */
final def isInterpreterWrapper = (
(isModule || isModuleClass)
&& owner.isPackageClass
&& nme.isReplWrapperName(name)
)
/** Is this symbol an effective root for fullname string?
*/
def isEffectiveRoot = isRoot || isEmptyPackageClass

/** Term symbols with the exception of static parts of Java classes and packages.
*/
Expand Down Expand Up @@ -652,8 +660,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isModuleVar = hasFlag(MODULEVAR)

/** Is this symbol static (i.e. with no outer instance)? */
final def isStatic: Boolean =
hasFlag(STATIC) || isRoot || owner.isStaticOwner
def isStatic = (this hasFlag STATIC) || owner.isStaticOwner

/** Is this symbol a static constructor? */
final def isStaticConstructor: Boolean =
Expand Down Expand Up @@ -685,8 +692,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isConstant: Boolean = isStable && isConstantType(tpe.resultType)

/** Is this class nested in another class or module (not a package)? */
final def isNestedClass: Boolean =
isClass && !isRoot && !owner.isPackageClass
def isNestedClass = isClass && !owner.isPackageClass

/** Is this class locally defined?
* A class is local, if
Expand Down Expand Up @@ -2045,7 +2051,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

def fullNameString: String = {
def recur(sym: Symbol): String = {
if (sym.isRoot || sym.isRootPackage || sym == NoSymbol) sym.nameString
if (sym.isRootSymbol || sym == NoSymbol) sym.nameString
else if (sym.owner.isEffectiveRoot) sym.nameString
else recur(sym.effectiveOwner.enclClass) + "." + sym.nameString
}
Expand Down Expand Up @@ -2095,7 +2101,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
case rt => " <: " + rt
}
)
else if (isModule) moduleClass.infoString(tp)
else if (isModule) "" // avoid "object X of type X.type"
else tp match {
case PolyType(tparams, res) => typeParamsString(tp) + infoString(res)
case NullaryMethodType(res) => infoString(res)
Expand Down
101 changes: 64 additions & 37 deletions src/compiler/scala/reflect/internal/Types.scala
Expand Up @@ -904,6 +904,12 @@ trait Types extends api.Types { self: SymbolTable =>
else str
}

/** The string representation of this type when the direct object in a sentence.
* Normally this is no different from the regular representation, but modules
* read better as "object Foo" here and "Foo.type" the rest of the time.
*/
def directObjectString = safeToString

/** A test whether a type contains any unification type variables. */
def isGround: Boolean = this match {
case TypeVar(_, constr) =>
Expand Down Expand Up @@ -1224,8 +1230,7 @@ trait Types extends api.Types { self: SymbolTable =>
else if (sym.isModuleClass) sym.fullNameString + "."
else sym.nameString + ".this."
override def safeToString: String =
if (sym.isRoot) "<root>"
else if (sym.isEmptyPackageClass) "<empty>"
if (sym.isEffectiveRoot) "" + sym.name
else super.safeToString
override def narrow: Type = this
override def kind = "ThisType"
Expand Down Expand Up @@ -1851,6 +1856,35 @@ trait Types extends api.Types { self: SymbolTable =>
// advantage to call TypeRef directly.
override def typeConstructor = TypeRef(pre, sym, Nil)
}

class ModuleTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef {
require(sym.isModuleClass, sym)
private[this] var narrowedCache: Type = _
override def isStable = true
override def narrow = {
if (narrowedCache eq null)
narrowedCache = singleType(pre, sym.sourceModule)

narrowedCache
}
final override def isNotNull = true
override protected def finishPrefix(rest: String) = objectPrefix + rest
override def directObjectString = super.safeToString
override def toLongString = toString
override def safeToString = narrow.toString
}
class PackageTypeRef(pre0: Type, sym0: Symbol) extends ModuleTypeRef(pre0, sym0) {
require(sym.isPackageClass, sym)
override protected def finishPrefix(rest: String) = packagePrefix + rest
}
class RefinementTypeRef(sym0: Symbol) extends NoArgsTypeRef(NoType, sym0) with ClassTypeRef {
require(sym.isRefinementClass, sym)

// I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers
override protected def normalizeImpl: Type = sym.info.normalize
override protected def finishPrefix(rest: String) = "" + thisInfo
}

class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType {
// A reference (in a Scala program) to a type that has type parameters, but where the reference
// does not include type arguments. Note that it doesn't matter whether the symbol refers
Expand Down Expand Up @@ -1898,10 +1932,6 @@ trait Types extends api.Types { self: SymbolTable =>
// !!! There are scaladoc-created symbols arriving which violate this require.
// require(sym.isClass, sym)

override protected def normalizeImpl: Type =
if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers
else super.normalizeImpl

override def baseType(clazz: Symbol): Type =
if (sym == clazz) this
else transform(sym.info.baseType(clazz))
Expand Down Expand Up @@ -2147,12 +2177,15 @@ trait Types extends api.Types { self: SymbolTable =>
}
}

private def preString = (
// ensure that symbol is not a local copy with a name coincidence
if (!settings.debug.value && shorthands(sym.fullName) && sym.ownerChain.forall(_.isClass)) ""
else pre.prefixString
// ensure that symbol is not a local copy with a name coincidence
private def needsPreString = (
settings.debug.value
|| !shorthands(sym.fullName)
|| sym.ownerChain.exists(s => !s.isClass)
)
private def preString = if (needsPreString) pre.prefixString else ""
private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]")

def refinementString = (
if (sym.isStructuralRefinement) (
decls filter (sym => sym.isPossibleInRefinement && sym.isPublic)
Expand All @@ -2162,12 +2195,9 @@ trait Types extends api.Types { self: SymbolTable =>
else ""
)

private def finishPrefix(rest: String) = (
if (sym.isPackageClass) packagePrefix + rest
else if (sym.isModuleClass) objectPrefix + rest
else if (!sym.isInitialized) rest
else if (sym.isAnonymousClass && !phase.erasedTypes) parentsString(thisInfo.parents) + refinementString
else if (sym.isRefinementClass) "" + thisInfo
protected def finishPrefix(rest: String) = (
if (sym.isInitialized && sym.isAnonymousClass && !phase.erasedTypes)
parentsString(thisInfo.parents) + refinementString
else rest
)
private def customToString = this match {
Expand Down Expand Up @@ -2227,6 +2257,9 @@ trait Types extends api.Types { self: SymbolTable =>
else {
if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef
else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef
else if (sym.isRefinementClass) new RefinementTypeRef(sym)
else if (sym.isPackageClass) new PackageTypeRef(pre, sym)
else if (sym.isModuleClass) new ModuleTypeRef(pre, sym)
else new NoArgsTypeRef(pre, sym) with ClassTypeRef
}
})
Expand Down Expand Up @@ -4603,31 +4636,22 @@ trait Types extends api.Types { self: SymbolTable =>
object adaptToNewRunMap extends TypeMap {

private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = {
if (phase.flatClasses) {
if (phase.flatClasses || sym.isRootSymbol || (pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass)
sym
} else if (sym == definitions.RootClass) {
definitions.RootClass
} else if (sym == definitions.RootPackage) {
definitions.RootPackage
} else if (sym.isModuleClass) {
else if (sym.isModuleClass) {
val sourceModule1 = adaptToNewRun(pre, sym.sourceModule)
var result = sourceModule1.moduleClass
if (result == NoSymbol) result = sourceModule1.initialize.moduleClass
if (result != NoSymbol) result
else {

sourceModule1.moduleClass orElse sourceModule1.initialize.moduleClass orElse {
val msg = "Cannot adapt module class; sym = %s, sourceModule = %s, sourceModule.moduleClass = %s => sourceModule1 = %s, sourceModule1.moduleClass = %s"
debuglog(msg.format(sym, sym.sourceModule, sym.sourceModule.moduleClass, sourceModule1, sourceModule1.moduleClass))
sym
}
} else if ((pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass) {
sym
} else {
var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true)
if (rebind0 == NoSymbol) {
}
else {
var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) orElse {
if (sym.isAliasType) throw missingAliasException
debugwarn(pre+"."+sym+" does no longer exist, phase = "+phase)
throw new MissingTypeControl // For build manager and presentation compiler purposes
//assert(false, pre+"."+sym+" does no longer exist, phase = "+phase)
}
/** The two symbols have the same fully qualified name */
def corresponds(sym1: Symbol, sym2: Symbol): Boolean =
Expand All @@ -4646,12 +4670,10 @@ trait Types extends api.Types { self: SymbolTable =>
", rebind = " + rebind0.fullLocationString
)
}
val rebind = rebind0.suchThat(sym => sym.isType || sym.isStable)
if (rebind == NoSymbol) {
rebind0.suchThat(sym => sym.isType || sym.isStable) orElse {
debuglog("" + phase + " " +phase.flatClasses+sym.owner+sym.name+" "+sym.isType)
throw new MalformedType(pre, sym.nameString)
}
rebind
}
}
def apply(tp: Type): Type = tp match {
Expand Down Expand Up @@ -5472,9 +5494,14 @@ trait Types extends api.Types { self: SymbolTable =>
case _: ClassSymbol =>
if (isRaw(sym1, tr1.args))
isSubType(rawToExistential(tp1), tp2, depth)
else
sym1.name == tpnme.REFINE_CLASS_NAME &&
else if (sym1.isModuleClass) tp2 match {
case SingleType(_, sym2) => sym1 == sym2
case _ => false
}
else if (sym1.isRefinementClass)
isSubType(sym1.info, tp2, depth)
else false

case _: TypeSymbol =>
if (sym1 hasFlag DEFERRED) {
val tp1a = tp1.bounds.hi
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
Expand Up @@ -105,7 +105,7 @@ abstract class BrowsingLoaders extends SymbolLoaders {
*/
override def enterToplevelsFromSource(root: Symbol, name: String, src: AbstractFile) {
try {
if (root == definitions.RootClass || root == definitions.EmptyPackageClass)
if (root.isEffectiveRoot) // RootClass or EmptyPackageClass
super.enterToplevelsFromSource(root, name, src)
else
browseTopLevel(root, src)
Expand Down
8 changes: 2 additions & 6 deletions src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
Expand Up @@ -30,15 +30,11 @@ abstract class SymbolLoaders {
member
}

private def realOwner(root: Symbol): Symbol = {
if (root.isRoot) definitions.EmptyPackageClass else root
}

/** Enter class with given `name` into scope of `root`
* and give them `completer` as type.
*/
def enterClass(root: Symbol, name: String, completer: SymbolLoader): Symbol = {
val owner = realOwner(root)
val owner = root.ownerOfNewSymbols
val clazz = owner.newClass(newTypeName(name))
clazz setInfo completer
enterIfNew(owner, clazz, completer)
Expand All @@ -48,7 +44,7 @@ abstract class SymbolLoaders {
* and give them `completer` as type.
*/
def enterModule(root: Symbol, name: String, completer: SymbolLoader): Symbol = {
val owner = realOwner(root)
val owner = root.ownerOfNewSymbols
val module = owner.newModule(newTermName(name))
module setInfo completer
module.moduleClass setInfo moduleClassLoader
Expand Down

0 comments on commit f7535f7

Please sign in to comment.