From 296b7061ccef8600c011140fa6fd64afec244ed0 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 5 Apr 2012 15:50:10 -0700 Subject: A boatload of work on Symbols and Flags. Finally my dream of orderliness is within sight. It's all pretty self-explanatory. More polymorphism, more immutable identity, more invariants. --- .../scala/reflect/internal/Definitions.scala | 14 +- src/compiler/scala/reflect/internal/Flags.scala | 80 +- src/compiler/scala/reflect/internal/HasFlags.scala | 109 +-- .../scala/reflect/internal/Importers.scala | 10 +- .../scala/reflect/internal/SymbolCreations.scala | 106 +++ .../scala/reflect/internal/SymbolFlags.scala | 237 ++++++ .../scala/reflect/internal/SymbolTable.scala | 9 + src/compiler/scala/reflect/internal/Symbols.scala | 852 +++++++++++---------- .../scala/reflect/internal/TreePrinters.scala | 2 +- .../reflect/internal/pickling/UnPickler.scala | 27 +- .../reflect/runtime/SynchronizedSymbols.scala | 47 +- src/compiler/scala/tools/nsc/Global.scala | 4 - src/compiler/scala/tools/nsc/ast/Reifiers.scala | 2 +- src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 2 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 13 +- .../scala/tools/nsc/backend/icode/TypeKinds.scala | 2 +- .../scala/tools/nsc/transform/AddInterfaces.scala | 11 +- .../scala/tools/nsc/transform/ExplicitOuter.scala | 2 +- .../scala/tools/nsc/transform/Flatten.scala | 2 +- .../tools/nsc/typechecker/ContextErrors.scala | 2 +- .../scala/tools/nsc/typechecker/Infer.scala | 2 +- .../scala/tools/nsc/typechecker/Namers.scala | 8 +- .../tools/nsc/typechecker/NamesDefaults.scala | 4 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 4 +- .../scala/tools/nsc/typechecker/Typers.scala | 6 +- 25 files changed, 970 insertions(+), 587 deletions(-) create mode 100644 src/compiler/scala/reflect/internal/SymbolCreations.scala create mode 100644 src/compiler/scala/reflect/internal/SymbolFlags.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 8ea3cd511a..0224f9158e 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -138,6 +138,12 @@ trait Definitions extends reflect.api.StandardDefinitions { // symbols related to packages var emptypackagescope: Scope = null //debug + // TODO - having these as objects means they elude the attempt to + // add synchronization in SynchronizedSymbols. But we should either + // flip on object overrides or find some other accomodation, because + // lazy vals are unnecessarily expensive relative to objects and it + // is very beneficial for a handful of bootstrap symbols to have + // first class identities sealed trait WellKnownSymbol extends Symbol { this initFlags TopLevelCreationFlags } @@ -148,7 +154,7 @@ trait Definitions extends reflect.api.StandardDefinitions { } // This is the package _root_. The actual root cannot be referenced at // the source level, but _root_ is essentially a function => . - final object RootPackage extends ModuleSymbol(NoSymbol, NoPosition, nme.ROOTPKG) with RootSymbol { + final object RootPackage extends PackageSymbol(NoSymbol, NoPosition, nme.ROOTPKG) with RootSymbol { this setInfo NullaryMethodType(RootClass.tpe) RootClass.sourceModule = this @@ -160,7 +166,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // 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 { + final object RootClass extends PackageClassSymbol(NoSymbol, NoPosition, tpnme.ROOT) with RootSymbol { this setInfo rootLoader override def isRoot = true @@ -170,10 +176,10 @@ trait Definitions extends reflect.api.StandardDefinitions { override def ownerOfNewSymbols = EmptyPackageClass } // The empty package, which holds all top level types without given packages. - final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { + final object EmptyPackage extends PackageSymbol(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 { + final object EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { override def isEffectiveRoot = true override def isEmptyPackageClass = true } diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala index ce1c8d0908..38f9ec6669 100644 --- a/src/compiler/scala/reflect/internal/Flags.scala +++ b/src/compiler/scala/reflect/internal/Flags.scala @@ -174,6 +174,9 @@ class Flags extends ModifierFlags { final val LateShift = 47L final val AntiShift = 56L + // Flags which sketchily share the same slot + val OverloadedFlagsMask = 0L | BYNAMEPARAM | CONTRAVARIANT | DEFAULTPARAM | EXISTENTIAL | IMPLCLASS + // ------- late flags (set by a transformer phase) --------------------------------- // // Summary of when these are claimed to be first used. @@ -206,12 +209,24 @@ class Flags extends ModifierFlags { // ------- masks ----------------------------------------------------------------------- + /** To be a little clearer to people who aren't habitual bit twiddlers. + */ + final val AllFlags = -1L + /** These flags can be set when class or module symbol is first created. * They are the only flags to survive a call to resetFlags(). */ final val TopLevelCreationFlags: Long = MODULE | PACKAGE | FINAL | JAVA + // TODO - there's no call to slap four flags onto every package. + final val PackageFlags: Long = TopLevelCreationFlags + + // FINAL not included here due to possibility of object overriding. + // In fact, FINAL should not be attached regardless. We should be able + // to reconstruct whether an object was marked final in source. + final val ModuleFlags: Long = MODULE + /** These modifiers can be set explicitly in source programs. This is * used only as the basis for the default flag mask (which ones to display * when printing a normal message.) @@ -220,15 +235,15 @@ class Flags extends ModifierFlags { PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED | OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY - /** These modifiers appear in TreePrinter output. */ - final val PrintableFlags: Long = - ExplicitFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO | - ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | BRIDGE | STATIC | VBRIDGE | SPECIALIZED | SYNCHRONIZED - /** The two bridge flags */ final val BridgeFlags = BRIDGE | VBRIDGE final val BridgeAndPrivateFlags = BridgeFlags | PRIVATE + /** These modifiers appear in TreePrinter output. */ + final val PrintableFlags: Long = + ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO | + ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED + /** When a symbol for a field is created, only these flags survive * from Modifiers. Others which may be applied at creation time are: * PRIVATE, LOCAL. @@ -264,7 +279,7 @@ class Flags extends ModifierFlags { final val ConstrFlags: Long = JAVA /** Module flags inherited by their module-class */ - final val ModuleToClassFlags: Long = AccessFlags | MODULE | PACKAGE | CASE | SYNTHETIC | JAVA | FINAL + final val ModuleToClassFlags: Long = AccessFlags | TopLevelCreationFlags | CASE | SYNTHETIC def getterFlags(fieldFlags: Long): Long = ACCESSOR + ( if ((fieldFlags & MUTABLE) != 0) fieldFlags & ~MUTABLE & ~PRESUPER @@ -407,26 +422,43 @@ class Flags extends ModifierFlags { case _ => "" } - def flagsToString(flags: Long, privateWithin: String): String = { - var f = flags - val pw = - if (privateWithin == "") { - if ((flags & PrivateLocal) == PrivateLocal) { - f &= ~PrivateLocal - "private[this]" - } else if ((flags & ProtectedLocal) == ProtectedLocal) { - f &= ~ProtectedLocal - "protected[this]" - } else { - "" + def accessString(flags: Long, privateWithin: String)= ( + if (privateWithin == "") { + if ((flags & PrivateLocal) == PrivateLocal) "private[this]" + else if ((flags & ProtectedLocal) == ProtectedLocal) "protected[this]" + else if ((flags & PRIVATE) != 0) "private" + else if ((flags & PROTECTED) != 0) "protected" + else "" + } + else if ((flags & PROTECTED) != 0) "protected[" + privateWithin + "]" + else "private[" + privateWithin + "]" + ) + def nonAccessString(flags0: Long)(flagStringFn: Long => String): String = { + val flags = flags0 & ~AccessFlags + // Fast path for common case + if (flags == 0L) "" else { + var sb: StringBuilder = null + var i = 0 + while (i <= MaxBitPosition) { + val mask = rawFlagPickledOrder(i) + if ((flags & mask) != 0L) { + val s = flagStringFn(mask) + if (s.length > 0) { + if (sb eq null) sb = new StringBuilder append s + else if (sb.length == 0) sb append s + else sb append " " append s + } } - } else if ((f & PROTECTED) != 0L) { - f &= ~PROTECTED - "protected[" + privateWithin + "]" - } else { - "private[" + privateWithin + "]" + i += 1 } - List(flagsToString(f), pw) filterNot (_ == "") mkString " " + if (sb eq null) "" else sb.toString + } + } + + def flagsToString(flags: Long, privateWithin: String): String = { + val access = accessString(flags, privateWithin) + val nonAccess = flagsToString(flags & ~AccessFlags) + List(nonAccess, access) filterNot (_ == "") mkString " " } // List of the raw flags, in pickled order diff --git a/src/compiler/scala/reflect/internal/HasFlags.scala b/src/compiler/scala/reflect/internal/HasFlags.scala index 8affd66cd5..2f574b6bfa 100644 --- a/src/compiler/scala/reflect/internal/HasFlags.scala +++ b/src/compiler/scala/reflect/internal/HasFlags.scala @@ -1,76 +1,6 @@ package scala.reflect package internal -/** ISSUE #1: Flag names vs. Test method names - * - * The following methods from Symbol have a name of - * the form isFoo where FOO is the name of a flag, but where the method - * body tests for more than whether the flag is set. - * - * There are two possibilities with such methods. Either the extra - * tests are strictly to partition among overloaded flags (which is - * the case we can live with in the short term, if each such flag's - * partitioning assumptions are documented) or they aren't. - * - * The second case implies that "x hasFlag FOO" and "x.isFoo" have - * different semantics, and this we can't live with, because even if - * we're smart enough to avoid being tripped up by that, the next guy isn't. - * - * No extreme measures necessary, only renaming isFoo to something - * which hews more closely to its implementation. (Or renaming the flag.) - * - // Defined in the compiler Symbol - // - final def isLabel = isMethod && !hasAccessorFlag && hasFlag(LABEL) - final def isLocal: Boolean = owner.isTerm - final def isModuleVar: Boolean = isVariable && hasFlag(MODULEVAR) - final def isStable = - isTerm && - !hasTraitFlag && - (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) && - !(tpe.isVolatile && !hasAnnotation(uncheckedStableClass)) - final def isStatic: Boolean = - hasFlag(STATIC) || isRoot || owner.isStaticOwner - override final def isTrait: Boolean = - isClass && hasFlag(TRAIT | notDEFERRED) // A virtual class becomes a trait (part of DEVIRTUALIZE) - - // Defined in the library Symbol - // - def isTrait: Boolean = isClass && hasFlag(TRAIT) // refined later for virtual classes. - final def isContravariant = isType && hasFlag(CONTRAVARIANT) - final def isCovariant = isType && hasFlag(COVARIANT) - final def isMethod = isTerm && hasFlag(METHOD) - final def isModule = isTerm && hasFlag(MODULE) - final def isPackage = isModule && hasFlag(PACKAGE) - * - */ - -/** ISSUE #2: Implicit flag relationships must be made explicit. - * - * For instance, every time the MODULE flag is set, the FINAL flag is - * set along with it: - * - .setFlag(FINAL | MODULE | PACKAGE | JAVA) - .setFlag(FINAL | MODULE | PACKAGE | JAVA).setInfo(rootLoader) - new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) - new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) - val m = new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) - setFlag(module.getFlag(ModuleToClassFlags) | MODULE | FINAL) - sourceModule.flags = MODULE | FINAL - - * However the same is not true of when the MODULE flag is cleared: - - sym.resetFlag(MODULE) - .setFlag(sym.flags | STABLE).resetFlag(MODULE) - sym.resetFlag(MODULE | FINAL | CASE) - - * It's not relevant whether this example poses any issues: we must - * not tolerate these uncertainties. If the flags are to move together - * then both setting and clearing have to be encapsulated. If there - * is a useful and used distinction between the various permutations - * of on and off, then it must be documented. It's the only way! - */ - import Flags._ /** Common code utilized by Modifiers (which carry the flags associated @@ -165,26 +95,20 @@ trait HasFlags { // which must have been a bug. def isPublic = hasNoFlags(PRIVATE | PROTECTED) && !hasAccessBoundary - // Renamed the Modifiers impl from isArgument. - def isParameter = hasFlag(PARAM) - // Removed isClass qualification since the flag isn't overloaded and // sym.isClass is enforced in Namers#validate. def isSealed = hasFlag(SEALED) // Removed !isClass qualification since the flag isn't overloaded. - def isDeferred = hasFlag(DEFERRED ) + def isDeferred = hasFlag(DEFERRED) // Dropped isTerm condition because flag isn't overloaded. def isAbstractOverride = hasFlag(ABSOVERRIDE) def isAnyOverride = hasFlag(OVERRIDE | ABSOVERRIDE) - def isDefaultInit = hasFlag(DEFAULTINIT) // Disambiguating: DEFAULTPARAM, TRAIT def hasDefault = hasAllFlags(DEFAULTPARAM | PARAM) def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM) - def hasTraitFlag = hasFlag(TRAIT) - def hasDefaultFlag = hasFlag(DEFAULTPARAM) // Straightforwardly named accessors already being used differently. // These names are most likely temporary. @@ -193,16 +117,9 @@ trait HasFlags { def hasLocalFlag = hasFlag(LOCAL) def hasModuleFlag = hasFlag(MODULE) def hasPackageFlag = hasFlag(PACKAGE) - def hasPreSuperFlag = hasFlag(PRESUPER) def hasStableFlag = hasFlag(STABLE) def hasStaticFlag = hasFlag(STATIC) - // Disambiguating: BYNAMEPARAM, CAPTURED, COVARIANT. - def isByNameParam = hasAllFlags(BYNAMEPARAM | PARAM) - // Nope, these aren't going to fly: - // def isCapturedVariable = hasAllFlags(CAPTURED | MUTABLE) - // def isCovariant = hasFlag(COVARIANT) && hasNoFlags(PARAM | MUTABLE) - // Disambiguating: LABEL, CONTRAVARIANT, INCONSTRUCTOR def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag // Cannot effectively disambiguate the others at this level. @@ -212,23 +129,13 @@ trait HasFlags { // Name def isJavaDefined = hasFlag(JAVA) - // Keeping some potentially ambiguous names around so as not to break - // the rest of the world + // Backward compat section + @deprecated( "Use isTrait", "2.10.0") + def hasTraitFlag = hasFlag(TRAIT) + @deprecated("Use hasDefault", "2.10.0") + def hasDefaultFlag = hasFlag(DEFAULTPARAM) @deprecated("", "2.9.0") def isAbstract = hasFlag(ABSTRACT) - // Problematic: - // ABSTRACT and DEFERRED too easy to confuse, and - // ABSTRACT + OVERRIDE ==> ABSOVERRIDE adds to it. - // - // final def isAbstractClass = isClass && hasFlag(ABSTRACT) - // def isAbstractType = false // to be overridden - - // Question: - // Which name? All other flags are isFlag so it's probably a mistake to - // vary from that, but isAccessor does sound like it includes the other - // *ACCESSOR flags. Perhaps something like isSimpleAccessor. - // - // def isAccessor = hasFlag(ACCESSOR ) - // final def isGetterOrSetter = hasAccessorFlag + @deprecated("Use isValueParameter or isTypeParameter", "2.10.0") + def isParameter = hasFlag(PARAM) } - diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 04381937d1..5dcff804a8 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -63,7 +63,7 @@ trait Importers { self: SymbolTable => } myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags) case x: from.ModuleClassSymbol => - val mysym = myowner.newModuleClassSymbol(myname.toTypeName, mypos, myflags) + val mysym = myowner.newModuleClass(myname.toTypeName, mypos, myflags) symMap(x) = mysym mysym.sourceModule = importSymbol(x.sourceModule) mysym @@ -109,14 +109,18 @@ trait Importers { self: SymbolTable => val owner = sym.owner var scope = if (owner.isClass && !owner.isRefinementClass) owner.info else from.NoType var existing = scope.decl(name) - if (sym.isPackageClass || sym.isModuleClass) existing = existing.moduleClass + if (sym.isModuleClass) + existing = existing.moduleClass + if (!existing.exists) scope = from.NoType val myname = importName(name) val myowner = importSymbol(owner) val myscope = if (scope != from.NoType && !(myowner hasFlag Flags.LOCKED)) myowner.info else NoType var myexisting = if (myscope != NoType) myowner.info.decl(myname) else NoSymbol // cannot load myexisting in general case, because it creates cycles for methods - if (sym.isPackageClass || sym.isModuleClass) myexisting = importSymbol(sym.sourceModule).moduleClass + if (sym.isModuleClass) + myexisting = importSymbol(sym.sourceModule).moduleClass + if (!sym.isOverloaded && myexisting.isOverloaded) { myexisting = if (sym.isMethod) { diff --git a/src/compiler/scala/reflect/internal/SymbolCreations.scala b/src/compiler/scala/reflect/internal/SymbolCreations.scala new file mode 100644 index 0000000000..62fee9d7f3 --- /dev/null +++ b/src/compiler/scala/reflect/internal/SymbolCreations.scala @@ -0,0 +1,106 @@ + /* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect +package internal + +import scala.collection.{ mutable, immutable } +import scala.collection.mutable.ListBuffer +import util.Statistics._ +import Flags._ +import api.Modifier +import scala.tools.util.StringOps.{ ojoin } + +trait SymbolCreations { + self: SymbolTable => + + import definitions._ + + /** Symbol creation interface, possibly better moved somewhere else. + * It'd be nice if we had virtual classes, but since we + * don't: these methods insulate the direct instantiation of the symbols + * (which may be overridden, e.g. in SynchronizedSymbols) from the + * enforcement of preconditions and choice of symbol constructor based + * on flags, which are (or should be) final so they can be reasoned about + * without lots of surprises. + */ + trait SymbolCreatorInterface { + // Fallbacks; more precise creators should normally be called. + protected def createTypeSymbol(name: TypeName, pos: Position, newFlags: Long): TypeSymbol + protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol + + // I believe all but rogue TypeSymbols are one of: ClassSymbol, AbstractTypeSymbol, AliasTypeSymbol, or TypeSkolem. + protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol + protected def createAliasTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AliasTypeSymbol + protected def createTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position, newFlags: Long): TypeSkolem + protected def createClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol + + // More specific ClassSymbols. + // TODO - AnonymousClassSymbol. + // TODO maybe - PackageObjects, but that one cost me a lot of time when I tried it before + // because it broke reification some way I couldn't see. + protected def createModuleClassSymbol(name: TypeName, pos: Position, newFlags: Long): ModuleClassSymbol + protected def createPackageClassSymbol(name: TypeName, pos: Position, newFlags: Long): PackageClassSymbol + protected def createRefinementClassSymbol(pos: Position, newFlags: Long): RefinementClassSymbol + + // Distinguished term categories include methods, modules, packages, package objects, + // value parameters, and values (including vals, vars, and lazy vals.) + protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol + protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol + protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): PackageSymbol + + // TODO + // protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol + // protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol + } + + trait SymbolCreator extends SymbolCreatorInterface { + self: Symbol => + + /*** Predictable symbol creation. + * + * newTermSymbol, newClassSymbol, and newNonClassSymbol all create symbols based + * only on the flags (for reconstruction after reification.) It would be nice to + * combine the last two into newTypeSymbol, but this requires some flag which allows us + * to distinguish classes and type aliases, which as yet does not exist. + * + * The fundamental flags used to determine which Symbol subclass to instantiate are: + * METHOD, PACKAGE, MODULE, PARAM, DEFERRED. + */ + final def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = { + if ((newFlags & METHOD) != 0) + createMethodSymbol(name, pos, newFlags) + else if ((newFlags & PACKAGE) != 0) + createPackageSymbol(name, pos, newFlags | PackageFlags) + else if ((newFlags & MODULE) != 0) + createModuleSymbol(name, pos, newFlags) + else if ((newFlags & PARAM) != 0) + createValueParameterSymbol(name, pos, newFlags) + else + createValueMemberSymbol(name, pos, newFlags) + } + + final def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = { + if (name == tpnme.REFINE_CLASS_NAME) + createRefinementClassSymbol(pos, newFlags) + else if ((newFlags & PACKAGE) != 0) + createPackageClassSymbol(name, pos, newFlags | PackageFlags) + else if ((newFlags & MODULE) != 0) + createModuleClassSymbol(name, pos, newFlags) + else + createClassSymbol(name, pos, newFlags) + } + + final def newNonClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol = { + if ((newFlags & DEFERRED) != 0) + createAbstractTypeSymbol(name, pos, newFlags) + else + createAliasTypeSymbol(name, pos, newFlags) + } + + def newTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol = + newNonClassSymbol(name, pos, newFlags) + } +} diff --git a/src/compiler/scala/reflect/internal/SymbolFlags.scala b/src/compiler/scala/reflect/internal/SymbolFlags.scala new file mode 100644 index 0000000000..0b49ee2505 --- /dev/null +++ b/src/compiler/scala/reflect/internal/SymbolFlags.scala @@ -0,0 +1,237 @@ + /* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect +package internal + +import scala.collection.{ mutable, immutable } +import scala.collection.mutable.ListBuffer +import util.Statistics._ +import Flags._ +import api.Modifier +import scala.tools.util.StringOps.{ ojoin } + +trait SymbolFlags { + self: SymbolTable => + + import definitions._ + + /** Not mixed in under normal conditions; a powerful debugging aid. + */ + trait FlagVerifier extends SymbolFlagLogic { + this: Symbol => + + private def assert0(cond: Boolean, message: => Any) { + if (!cond) { + Console.err.println("[flag verification failure]\n%s\n%s\n".format(atPhaseStackMessage, message)) + (new Throwable).getStackTrace.take(13).drop(3).foreach(println) + println("") + } + } + + protected def verifyChange(isAdd: Boolean, mask: Long, before: Long) { + val after = if (isAdd) before | mask else before & ~mask + val added = after & ~before + val removed = before & ~after + val ignored = mask & ~added & ~removed + val error = ( + (added & OverloadedFlagsMask) != 0 || (removed & OverloadedFlagsMask) != 0 + // || (ignored != 0) + ) + val addString = if (added == 0) "" else "+(" + flagsToString(added) + ")" + val removeString = if (removed == 0) "" else "-(" + flagsToString(removed) + ")" + val changeString = if (added == 0 && removed == 0) "no change" else addString + " " + removeString + + if (error) { + val templ = ( + """| symbol: %s %s in %s + | call: %s(%s) + | flags: %s + | result: %s""".stripMargin + ) + + assert0(false, templ.format( + shortSymbolClass, + name.decode, + owner, + if (isAdd) "+" else "-", + flagsToString(mask), + flagsToString(before), + changeString + )) + } + } + + protected def verifyFlags(what: String) { + assert0(this hasAllFlags alwaysHasFlags, symbolCreationString + "\n always=%s, what=%s\n".format(flagsToString(alwaysHasFlags), what)) + if (this hasFlag neverHasFlags) { + val hasRaw = (rawflags & neverHasFlags) != 0 + assert0(!hasRaw, symbolCreationString + "\n never=%s, what=%s".format(flagsToString(neverHasFlags), what)) + } + } + override def initFlags(mask: Long): this.type = { + super.initFlags(mask) + verifyFlags("initFlags(" + flagsToString(mask) + ")") + this + } + override def setFlag(mask: Long): this.type = { + verifyChange(true, mask, rawflags) + super.setFlag(mask) + verifyFlags("setFlag(" + flagsToString(mask) + ")") + this + } + override def resetFlag(mask: Long): this.type = { + verifyChange(false, mask, rawflags) + super.resetFlag(mask) + verifyFlags("resetFlag(" + flagsToString(mask) + ")") + this + } + override def flags_=(fs: Long) { + if ((fs & ~rawflags) != 0) + verifyChange(true, fs & ~rawflags, rawflags) + if ((rawflags & ~fs) != 0) + verifyChange(false, rawflags & ~fs, rawflags) + + super.flags_=(fs) + verifyFlags("flags_=(" + flagsToString(fs) + ")") + } + } + + /** A distinguishing flag is one which the mixing class must always + * have, and which no other symbol class is allowed to have. + */ + trait DistinguishingFlag extends SymbolFlagLogic { + this: Symbol => + + def distinguishingFlag: Long + override protected def alwaysHasFlags = super.alwaysHasFlags | distinguishingFlag + override protected def neverHasFlags = super.neverHasFlags & ~distinguishingFlag + } + + trait SymbolFlagLogic { + this: Symbol => + + protected def alwaysHasFlags: Long = 0L + protected def neverHasFlags: Long = METHOD | MODULE + + def flagStringFn(flag: Long): String = { + val res = flag match { + // "" + case BYNAMEPARAM => + if (this.isValueParameter) "" + else if (this.isTypeParameter) "" + else "" + // "" + case CONTRAVARIANT => + if (this.isLabel) "