diff options
Diffstat (limited to 'src')
11 files changed, 129 insertions, 104 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 37c87633e2..75c106dc2b 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -55,64 +55,9 @@ abstract class NodePrinters { str.toString } def symflags(tree: Tree): String = { - val sym = tree.symbol val buf = new StringBuffer - if (sym hasFlag IMPLICIT ) buf.append(" | IMPLICIT") - if (sym hasFlag FINAL ) buf.append(" | FINAL") - if (sym hasFlag PRIVATE ) buf.append(" | PRIVATE") - if (sym hasFlag PROTECTED ) buf.append(" | PROTECTED") - - if (sym hasFlag SEALED ) buf.append(" | SEALED") - if (sym hasFlag OVERRIDE ) buf.append(" | OVERRIDE") - if (sym hasFlag CASE ) buf.append(" | CASE") - if (sym hasFlag ABSTRACT ) buf.append(" | ABSTRACT") - - if (sym hasFlag DEFERRED ) buf.append(" | DEFERRED") - if (sym hasFlag METHOD ) buf.append(" | METHOD") - if (sym hasFlag MODULE ) buf.append(" | MODULE") - if (sym hasFlag INTERFACE ) buf.append(" | INTERFACE") - - if (sym hasFlag MUTABLE ) buf.append(" | MUTABLE") - if (sym hasFlag PARAM ) buf.append(" | PARAM") - if (sym hasFlag PACKAGE ) buf.append(" | PACKAGE") - - if (sym hasFlag COVARIANT ) buf.append(" | COVARIANT") - if (sym hasFlag CAPTURED ) buf.append(" | CAPTURED") - if (sym hasFlag BYNAMEPARAM ) buf.append(" | BYNAMEPARAM") - if (sym hasFlag CONTRAVARIANT) buf.append(" | CONTRAVARIANT") - if (sym hasFlag LABEL ) buf.append(" | LABEL") - if (sym hasFlag INCONSTRUCTOR) buf.append(" | INCONSTRUCTOR") - if (sym hasFlag ABSOVERRIDE ) buf.append(" | ABSOVERRIDE") - if (sym hasFlag LOCAL ) buf.append(" | LOCAL") - if (sym hasFlag JAVA ) buf.append(" | JAVA") - if (sym hasFlag SYNTHETIC ) buf.append(" | SYNTHETIC") - if (sym hasFlag STABLE ) buf.append(" | STABLE") - if (sym hasFlag STATIC ) buf.append(" | STATIC") - - if (sym hasFlag CASEACCESSOR ) buf.append(" | CASEACCESSOR") - if (sym hasFlag TRAIT ) buf.append(" | TRAIT") - if (sym hasFlag DEFAULTPARAM ) buf.append(" | DEFAULTPARAM") - if (sym hasFlag BRIDGE ) buf.append(" | BRIDGE") - if (sym hasFlag ACCESSOR ) buf.append(" | ACCESSOR") - - if (sym hasFlag SUPERACCESSOR) buf.append(" | SUPERACCESSOR") - if (sym hasFlag PARAMACCESSOR) buf.append(" | PARAMACCESSOR") - if (sym hasFlag MODULEVAR ) buf.append(" | MODULEVAR") - if (sym hasFlag SYNTHETICMETH) buf.append(" | SYNTHETICMETH") - if (sym hasFlag LAZY ) buf.append(" | LAZY") - - if (sym hasFlag IS_ERROR ) buf.append(" | IS_ERROR") - if (sym hasFlag OVERLOADED ) buf.append(" | OVERLOADED") - if (sym hasFlag LIFTED ) buf.append(" | LIFTED") - - if (sym hasFlag MIXEDIN ) buf.append(" | MIXEDIN") - if (sym hasFlag EXISTENTIAL ) buf.append(" | EXISTENTIAL") - - if (sym hasFlag EXPANDEDNAME ) buf.append(" | EXPANDEDNAME") - if (sym hasFlag IMPLCLASS ) buf.append(" | IMPLCLASS") - if (sym hasFlag PRESUPER ) buf.append(" | PRESUPER") - if (sym hasFlag TRANS_FLAG ) buf.append(" | TRANS_FLAG") - if (sym hasFlag LOCKED ) buf.append(" | LOCKED") + val sym = tree.symbol + buf append flagsToString(sym.flags) val annots = ", annots=" + ( if (!sym.annotations.isEmpty) @@ -122,6 +67,7 @@ abstract class NodePrinters { (if (buf.length() > 2) buf.substring(3) else "0") + ", // flags=" + flagsToString(sym.flags) + annots } + def nodeinfo(tree: Tree): String = if (infolevel == InfoLevel.Quiet) "" else { diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index a1f260519b..95b87060f4 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -17,7 +17,9 @@ trait Matrix extends MatrixAdditions { import analyzer.Typer import CODE._ import Debug._ - import Flags.{ TRANS_FLAG, SYNTHETIC, MUTABLE } + import Flags.{ SYNTHETIC, MUTABLE } + + private[matching] val NO_EXHAUSTIVE = Flags.TRANS_FLAG /** Translation of match expressions. * @@ -101,7 +103,7 @@ trait Matrix extends MatrixAdditions { // redundancy check matrix.targets filter (_.isNotReached) foreach (cs => cunit.error(cs.body.pos, "unreachable code")) - // optimize performs squeezing and resets any remaining TRANS_FLAGs + // optimize performs squeezing and resets any remaining NO_EXHAUSTIVE tracing("handlePattern(" + selector + ")", matrix optimize dfatree) } @@ -115,15 +117,15 @@ trait Matrix extends MatrixAdditions { { private def ifNull[T](x: T, alt: T) = if (x == null) alt else x - // TRANS_FLAG communicates there should be no exhaustiveness checking - private def flags(checked: Boolean) = if (checked) Nil else List(TRANS_FLAG) + // NO_EXHAUSTIVE communicates there should be no exhaustiveness checking + private def flags(checked: Boolean) = if (checked) Nil else List(NO_EXHAUSTIVE) // Recording the symbols of the synthetics we create so we don't go clearing // anyone else's mutable flags. private val _syntheticSyms = mutable.HashSet[Symbol]() def clearSyntheticSyms() = { - _syntheticSyms foreach (_ resetFlag (TRANS_FLAG|MUTABLE)) - log("Cleared TRANS_FLAG/MUTABLE on " + _syntheticSyms.size + " synthetic symbols.") + _syntheticSyms foreach (_ resetFlag (NO_EXHAUSTIVE|MUTABLE)) + log("Cleared NO_EXHAUSTIVE/MUTABLE on " + _syntheticSyms.size + " synthetic symbols.") _syntheticSyms.clear() } def recordSyntheticSym(sym: Symbol): Symbol = { @@ -157,7 +159,7 @@ trait Matrix extends MatrixAdditions { val xs = for (Binding(lhs, rhs) <- info) yield - new PatternVar(lhs, Ident(rhs) setType lhs.tpe, !(rhs hasFlag TRANS_FLAG)) + new PatternVar(lhs, Ident(rhs) setType lhs.tpe, !(rhs hasFlag NO_EXHAUSTIVE)) new PatternVarGroup(xs) } diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index ee4eb64e89..d30bbfa79c 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -127,7 +127,6 @@ trait MatrixAdditions extends ast.TreeDSL }) } } - returning(lxtt transform tree)(_ => clearSyntheticSyms()) } } @@ -145,7 +144,7 @@ trait MatrixAdditions extends ast.TreeDSL class ExhaustivenessChecker(rep: Rep) { val Rep(tvars, rows) = rep - import Flags.{ MUTABLE, ABSTRACT, SEALED, TRANS_FLAG } + import Flags.{ MUTABLE, ABSTRACT, SEALED } private case class Combo(index: Int, sym: Symbol) { val isBaseClass = sym.tpe.baseClasses.toSet @@ -167,7 +166,7 @@ trait MatrixAdditions extends ast.TreeDSL private def requiresExhaustive(sym: Symbol) = { (sym.isMutable) && // indicates that have not yet checked exhaustivity - !(sym hasFlag TRANS_FLAG) && // indicates @unchecked + !(sym hasFlag NO_EXHAUSTIVE) && // indicates @unchecked (sym.tpe.typeSymbol.isSealed) && !isValueClass(sym.tpe.typeSymbol) // make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte } diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 169518b9ab..55ca66c608 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -28,7 +28,6 @@ trait ParallelMatching extends ast.TreeDSL import CODE._ import Types._ import Debug._ - import Flags.{ TRANS_FLAG } import PartialFunction._ /** Transition **/ @@ -124,8 +123,8 @@ trait ParallelMatching extends ast.TreeDSL (0 to count).toList map (i => if (i < count) createElemVar(i) else createSeqVar(i)) // for propagating "unchecked" to synthetic vars - def isChecked = !(sym hasFlag TRANS_FLAG) - def flags: List[Long] = List(TRANS_FLAG) filter (sym hasFlag _) + def isChecked = !(sym hasFlag NO_EXHAUSTIVE) + def flags: List[Long] = List(NO_EXHAUSTIVE) filter (sym hasFlag _) // this is probably where this actually belongs def createVar(tpe: Type, f: Symbol => Tree) = context.createVar(tpe, f, isChecked) diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index ec0939c2d6..c1d60a9fe1 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -206,7 +206,7 @@ trait Patterns extends ast.TreeDSL { // @pre: is not right-ignoring (no star pattern) ; no exhaustivity check override def simplify(pv: PatternVar) = { - pv.sym setFlag Flags.TRANS_FLAG + pv.sym setFlag NO_EXHAUSTIVE this rebindTo elems.foldRight(gen.mkNil)(listFolder) } override def description = "UnSeq(%s => %s)".format(tptArg, resTypesString) diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index f3b31d4bcd..c94e8e2528 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -42,7 +42,7 @@ package symtab // 27: ACCESSOR // 28: SUPERACCESSOR // 29: PARAMACCESSOR/M -// 30: MODULEVAR SYNTHETICMETH +// 30: MODULEVAR // 31: LAZY/M // 32: IS_ERROR // 33: OVERLOADED @@ -179,7 +179,7 @@ class Flags extends reflect.generic.Flags { case ACCESSOR => "<accessor>" // (1L << 27) case SUPERACCESSOR => "<superaccessor>" // (1L << 28) case PARAMACCESSOR => "<paramaccessor>" // (1L << 29) - case MODULEVAR => "<modulevar/syntheticmeth>" // (1L << 30) + case MODULEVAR => "<modulevar>" // (1L << 30) case LAZY => "lazy" // (1L << 31) case IS_ERROR => "<is_error>" // (1L << 32) case OVERLOADED => "<overloaded>" // (1L << 33) diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 81cd62d550..e84ae10cee 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -471,10 +471,11 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable => ((hasFlag(notPRIVATE | LIFTED) && !hasFlag(ACCESSOR | SUPERACCESSOR | MODULE) || isConstructor) || (hasFlag(LIFTED) && isModule && isMethod)) - /** Is this symbol a module variable ? - * MUTABLE is needed to partition overloaded flags MODULEVAR and SYNTHETICMETH. + /** Is this symbol a module variable? + * This used to have to test for MUTABLE to distinguish the overloaded + * MODULEVAR/SYNTHETICMETH flag, but now SYNTHETICMETH is gone. */ - final def isModuleVar: Boolean = hasAllFlags(MODULEVAR | MUTABLE) + final def isModuleVar = hasFlag(MODULEVAR) /** Is this symbol static (i.e. with no outer instance)? */ final def isStatic: Boolean = diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index a1f152c39c..d7a0ce0544 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -8,6 +8,7 @@ package typechecker import symtab.Flags import symtab.Flags._ +import scala.collection.mutable import scala.collection.mutable.ListBuffer /** <ul> @@ -38,41 +39,39 @@ trait SyntheticMethods extends ast.TreeDSL { // to override this method anyways. protected def typer : Typer = global.typer.asInstanceOf[Typer] + /** In general case classes/objects are not given synthetic equals methods if some + * non-AnyRef implementation is inherited. However if you let a case object inherit + * an implementation from a case class, it creates an asymmetric equals with all the + * associated badness: see ticket #883. So if it sees such a thing this has happened + * (by virtue of the symbol being in createdMethodSymbols) it re-overrides it with + * reference equality. + */ + private val createdMethodSymbols = new mutable.HashSet[Symbol] + /** Add the synthetic methods to case classes. Note that a lot of the * complexity herein is a consequence of case classes inheriting from * case classes, which has been deprecated as of Sep 11 2009. So when * the opportunity for removal arises, this can be simplified. */ def addSyntheticMethods(templ: Template, clazz: Symbol, context: Context): Template = { - - val localContext = if (reporter.hasErrors) context makeSilent false else context - val localTyper = newTyper(localContext) + val localContext = if (reporter.hasErrors) context makeSilent false else context + val localTyper = newTyper(localContext) def hasOverridingImplementation(meth: Symbol): Boolean = { val sym = clazz.info nonPrivateMember meth.name - sym.alternatives exists { sym => - sym != meth && !(sym hasFlag DEFERRED) && !(sym hasFlag (SYNTHETIC | SYNTHETICMETH)) && - (clazz.thisType.memberType(sym) matches clazz.thisType.memberType(meth)) + def isOverride(s: Symbol) = { + s != meth && !s.isDeferred && !s.isSynthetic && !createdMethodSymbols(s) && + (clazz.thisType.memberType(s) matches clazz.thisType.memberType(meth)) } + sym.alternatives exists isOverride } def syntheticMethod(name: Name, flags: Int, tpeCons: Symbol => Type) = newSyntheticMethod(name, flags | OVERRIDE, tpeCons) - /** Note: at this writing this is the only place the SYNTHETICMETH is ever created. - * The flag is commented "synthetic method, but without SYNTHETIC flag", an explanation - * for which I now attempt to reverse engineer the motivation. - * - * In general case classes/objects are not given synthetic equals methods if some - * non-AnyRef implementation is inherited. However if you let a case object inherit - * an implementation from a case class, it creates an asymmetric equals with all the - * associated badness: see ticket #883. So if it sees such a thing (which is marked - * SYNTHETICMETH) it re-overrides it with reference equality. - * - * In other words it only exists to support (deprecated) case class inheritance. - */ def newSyntheticMethod(name: Name, flags: Int, tpeCons: Symbol => Type) = { - val method = clazz.newMethod(clazz.pos.focus, name) setFlag (flags | SYNTHETICMETH) + val method = clazz.newMethod(clazz.pos.focus, name) setFlag flags + createdMethodSymbols += method method setInfo tpeCons(method) clazz.info.decls.enter(method) } @@ -284,7 +283,7 @@ trait SyntheticMethods extends ast.TreeDSL { // if there's a synthetic method in a parent case class, override its equality // with eq (see #883) val otherEquals = clazz.info.nonPrivateMember(Object_equals.name) - if (otherEquals.owner != clazz && (otherEquals hasFlag SYNTHETICMETH)) ts += equalsModuleMethod + if (otherEquals.owner != clazz && createdMethodSymbols(otherEquals)) ts += equalsModuleMethod } val methods = (if (clazz.isModuleClass) objectMethods else classMethods) ++ everywhereMethods diff --git a/src/compiler/scala/tools/nsc/util/FlagsUtil.scala b/src/compiler/scala/tools/nsc/util/FlagsUtil.scala index 613306e6cf..ed1cfac2b2 100644 --- a/src/compiler/scala/tools/nsc/util/FlagsUtil.scala +++ b/src/compiler/scala/tools/nsc/util/FlagsUtil.scala @@ -25,10 +25,6 @@ package util // x.isParameter ==> DEFAULTPARAM // x.isClass ==> TRAIT // -// 30: MODULEVAR SYNTHETICMETH -// x.isMutable ==> MODULEVAR -// x.isMethod ==> SYNTHETICMETH -// // 35: EXISTENTIAL MIXEDIN // x.isType ==> EXISTENTIAL // x.isTerm ==> MIXEDIN @@ -37,8 +33,94 @@ package util // x.isClass ==> IMPLCLASS // x.isTerm ==> PRESUPER +import scala.collection.{ mutable, immutable } import symtab.Flags.ExplicitFlags +class TransFlagManager[T <: Global](val global: T) { + import global._ + import definitions._ + + private var trackerStack: List[FlagTracker] = Nil + private def trackerString = trackerStack.mkString(" ") + + class FlagTracker(val name: String) { + private val mask = symtab.Flags.TRANS_FLAG + private val seen = new mutable.HashSet[Symbol] + + private def debug(msg: String) = if (settings.debug.value) log(msg) + private def trace(msg: String) = if (settings.debug.value && settings.verbose.value) log(msg) + private def isDebug = settings.debug.value + private def doWeOwnFlag = trackerStack.headOption exists (_ eq this) + private def isOK = trackerStack.isEmpty || (trackerStack.head eq this) + + def apply(sym: Symbol) = { + if (!isOK) + log("Testing " + sym.name + " for " + name + " flag, but not at top of stack: " + trackerString) + + sym hasFlag mask + } + def set(sym: Symbol) = { + if (!isOK) + log("Tried to set " + name + " but not at top of stack: " + trackerString) + + seen += sym + sym setFlag mask + } + def reset(sym: Symbol) = { + if (!isOK) + log("Tried to clear " + name + " but not at top of stack: " + trackerString) + + seen -= sym + sym resetFlag mask + } + def clear() { + if (!doWeOwnFlag && seen.nonEmpty) + log("Clearing " + seen.size + " " + name + " flags even though the stack is: " + trackerString) + + seen foreach (_ resetFlag mask) + seen.clear() + } + } + + def forceClear() = { + if (trackerStack.nonEmpty) { + log("Warning: force clearing the stack at " + phase + ": " + trackerString) + trackerStack foreach (_.clear()) + trackerStack = Nil + } + } + + def claimTransFlag(label: String): FlagTracker = { + if (trackerStack.isEmpty || trackerStack.head.name != label) + trackerStack ::= new FlagTracker(label) + + trackerStack.head + } + def releaseTransFlag(label: String): Boolean = { + trackerStack.isEmpty || { + if (trackerStack.head.name == label) { + trackerStack.head.clear() + trackerStack = trackerStack.tail + true + } + else { + log("Warning: trying to release " + label + " flag but the stack is: " + trackerStack.mkString(" ")) + false + } + } + } + def holdingTransFlag[U](label: String)(f: FlagTracker => U): U = { + try { + val t = claimTransFlag(label) + f(t) + } + finally { + releaseTransFlag(label) + } + } +} + + /** Some functions for generating comments and methods involving flags, * with the output determined by reflection so we can have a little more * assurance that documentation and debugging output match up with reality. diff --git a/src/library/scala/reflect/generic/Flags.scala b/src/library/scala/reflect/generic/Flags.scala index 405069f8b6..17530ff28c 100755 --- a/src/library/scala/reflect/generic/Flags.scala +++ b/src/library/scala/reflect/generic/Flags.scala @@ -60,7 +60,6 @@ class Flags extends ModifierFlags { final val SUPERACCESSOR = 0x10000000 // a super accessor final val MODULEVAR = 0x40000000 // for variables: is the variable caching a module value - final val SYNTHETICMETH = 0x40000000 // for methods: synthetic method, but without SYNTHETIC flag final val IS_ERROR = 0x100000000L // symbol is an error symbol final val OVERLOADED = 0x200000000L // symbol is overloaded @@ -69,7 +68,6 @@ class Flags extends ModifierFlags { // todo: make LIFTED = latePRIVATE? final val MIXEDIN = 0x800000000L // term member has been mixed in final val EXISTENTIAL = 0x800000000L // type is an existential parameter or skolem - final val EXPANDEDNAME = 0x1000000000L // name has been expanded with class suffix final val IMPLCLASS = 0x2000000000L // symbol is an implementation class final val TRANS_FLAG = 0x4000000000L // transient flag guaranteed to be reset after each phase. @@ -163,7 +161,7 @@ class Flags extends ModifierFlags { case ACCESSOR => "<accessor>" // (1L << 27) case SUPERACCESSOR => "<superaccessor>" // (1L << 28) case PARAMACCESSOR => "<paramaccessor>" // (1L << 29) - case MODULEVAR => "<modulevar/syntheticmeth>" // (1L << 30) + case MODULEVAR => "<modulevar>" // (1L << 30) case LAZY => "lazy" // (1L << 31) case IS_ERROR => "<is_error>" // (1L << 32) case OVERLOADED => "<overloaded>" // (1L << 33) diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala index 8027f0c4c1..218639e4a2 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala @@ -51,7 +51,6 @@ trait Flags { def isParamAccessor = hasFlag(0x20000000) def isModuleVar = hasFlag(0x40000000) // for variables: is the variable caching a module value - def isSyntheticMethod = hasFlag(0x40000000) // for methods: synthetic method, but without SYNTHETIC flag def isMonomorphic = hasFlag(0x40000000) // for type symbols: does not have type parameters def isLazy = hasFlag(0x80000000L) // symbol is a lazy val. can't have MUTABLE unless transformed by typer |