summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/compiler/scala/reflect/internal/NameManglers.scala23
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala23
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala14
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala720
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--test/pending/run/t2897.scala22
11 files changed, 432 insertions, 410 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 4ee717ce75..2e64b0eb6d 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -267,6 +267,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass
def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass
def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp)
+ def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf
def isJavaVarArgs(params: List[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe)
def isScalaVarArgs(params: List[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe)
diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala
index c09397e2c2..9ff2232840 100644
--- a/src/compiler/scala/reflect/internal/NameManglers.scala
+++ b/src/compiler/scala/reflect/internal/NameManglers.scala
@@ -80,8 +80,7 @@ trait NameManglers {
def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR
def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX
- /** !!! Foo$class$1 is an implClassName, I think. */
- def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX
+ def isImplClassName(name: Name) = stripAnonNumberSuffix(name) endsWith IMPL_CLASS_SUFFIX
def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX
def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING
def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX)
@@ -159,6 +158,26 @@ trait NameManglers {
else name
}
+ /** !!! I'm putting this logic in place because I can witness
+ * trait impls get lifted and acquiring names like 'Foo$class$1'
+ * while clearly still being what they were. It's only being used on
+ * isImplClassName. However, it's anyone's guess how much more
+ * widely this logic actually ought to be applied. Anything which
+ * tests for how a name ends is a candidate for breaking down once
+ * something is lifted from a method.
+ *
+ * TODO: resolve this significant problem.
+ */
+ def stripAnonNumberSuffix(name: Name): Name = {
+ val str = "" + name
+ if (str == "" || !str.endChar.isDigit) name
+ else {
+ val idx = name.lastPos('$')
+ if (idx < 0 || str.substring(idx + 1).exists(c => !c.isDigit)) name
+ else name.subName(0, idx)
+ }
+ }
+
def stripModuleSuffix(name: Name): Name = (
if (isModuleName(name)) name stripEnd MODULE_SUFFIX_STRING else name
)
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index 86c32ec3e6..254c2e3b7e 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -361,23 +361,15 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy
mkName(simple, div == '.') :: segments(rest, assumeTerm)
}
}
- private def bitmapName(n: Int, suffix: String): TermName =
- newTermName(BITMAP_PREFIX + suffix + n)
- /** The name of bitmaps for initialized (public or protected) lazy vals. */
- def bitmapName(n: Int): TermName = bitmapName(n, "")
+ def newBitmapName(bitmapPrefix: Name, n: Int) = bitmapPrefix append ("" + n)
- /** The name of bitmaps for initialized transient lazy vals. */
- def bitmapNameForTransient(n: Int): TermName = bitmapName(n, "trans$")
-
- /** The name of bitmaps for initialized private lazy vals. */
- def bitmapNameForPrivate(n: Int): TermName = bitmapName(n, "priv$")
-
- /** The name of bitmaps for checkinit values */
- def bitmapNameForCheckinit(n: Int): TermName = bitmapName(n, "init$")
-
- /** The name of bitmaps for checkinit values that have transient flag*/
- def bitmapNameForCheckinitTransient(n: Int): TermName = bitmapName(n, "inittrans$")
+ val BITMAP_PREFIX: String = "bitmap$"
+ val BITMAP_NORMAL: NameType = BITMAP_PREFIX + "" // initialization bitmap for public/protected lazy vals
+ val BITMAP_TRANSIENT: NameType = BITMAP_PREFIX + "trans$" // initialization bitmap for transient lazy vals
+ val BITMAP_PRIVATE: NameType = BITMAP_PREFIX + "priv$" // initialization bitmap for private lazy vals
+ val BITMAP_CHECKINIT: NameType = BITMAP_PREFIX + "init$" // initialization bitmap for checkinit values
+ val BITMAP_CHECKINIT_TRANSIENT: NameType = BITMAP_PREFIX + "inittrans$" // initialization bitmap for transient checkinit values
/** The expanded name of `name` relative to this class `base` with given `separator`
*/
@@ -391,7 +383,6 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy
val ROOTPKG: TermName = "_root_"
/** Base strings from which synthetic names are derived. */
- val BITMAP_PREFIX = "bitmap$"
val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$"
val DEFAULT_GETTER_STRING = "$default$"
val DO_WHILE_PREFIX = "doWhile$"
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 81c718e65c..8175040a76 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -1317,8 +1317,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The symbol accessed by this accessor function, but with given owner type. */
final def accessed(ownerTp: Type): Symbol = {
- assert(hasAccessorFlag)
- ownerTp.decl(nme.getterToLocal(if (isSetter) nme.setterToGetter(name) else name))
+ assert(hasAccessorFlag, this)
+ ownerTp decl nme.getterToLocal(getterName)
}
/** The module corresponding to this module class (note that this
@@ -1349,6 +1349,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** If this is a lazy value, the lazy accessor; otherwise this symbol. */
def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this
+ /** If this is an accessor, the accessed symbol. Otherwise, this symbol. */
+ def accessedOrSelf: Symbol = if (hasAccessorFlag) accessed else this
+
/** For an outer accessor: The class from which the outer originates.
* For all other symbols: NoSymbol
*/
@@ -1646,10 +1649,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The getter of this value or setter definition in class `base`, or NoSymbol if
* none exists.
*/
- final def getter(base: Symbol): Symbol = {
- val getterName = if (isSetter) nme.setterToGetter(name) else nme.getterName(name)
- base.info.decl(getterName) filter (_.hasAccessorFlag)
- }
+ final def getter(base: Symbol): Symbol = base.info.decl(getterName) filter (_.hasAccessorFlag)
+
+ def getterName = if (isSetter) nme.setterToGetter(name) else nme.getterName(name)
/** The setter of this value or getter definition, or NoSymbol if none exists */
final def setter(base: Symbol): Symbol = setter(base, false)
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala
index 29438278d0..c0ccd6a4dc 100644
--- a/src/compiler/scala/reflect/internal/TreeInfo.scala
+++ b/src/compiler/scala/reflect/internal/TreeInfo.scala
@@ -17,7 +17,7 @@ abstract class TreeInfo {
val global: SymbolTable
import global._
- import definitions.{ isVarArgsList, ThrowableClass }
+ import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass }
/* Does not seem to be used. Not sure what it does anyway.
def isOwnerDefinition(tree: Tree): Boolean = tree match {
@@ -303,6 +303,15 @@ abstract class TreeInfo {
case _ => false
}
+ /** If this tree represents a type application (after unwrapping
+ * any applies) the first type argument. Otherwise, EmptyTree.
+ */
+ def firstTypeArg(tree: Tree): Tree = tree match {
+ case Apply(fn, _) => firstTypeArg(fn)
+ case TypeApply(_, targ :: _) => targ
+ case _ => EmptyTree
+ }
+
/** Does this argument list end with an argument of the form <expr> : _* ? */
def isWildcardStarArgList(trees: List[Tree]) =
trees.nonEmpty && isWildcardStarArg(trees.last)
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index c3aae2b65e..5452087aa3 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -246,7 +246,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
if (bmps.length > n)
bmps(n)
else {
- val sym = meth.newVariable(meth.pos, nme.bitmapName(n)).setInfo(IntClass.tpe)
+ val sym = meth.newVariable(meth.pos, nme.newBitmapName(nme.BITMAP_NORMAL, n)).setInfo(IntClass.tpe)
atPhase(currentRun.typerPhase) {
sym addAnnotation VolatileAttr
}
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 8dbc34d9d1..0181c80bff 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -9,7 +9,6 @@ package transform
import symtab._
import Flags._
import scala.collection.{ mutable, immutable }
-import scala.collection.mutable.ListBuffer
abstract class Mixin extends InfoTransform with ast.TreeDSL {
import global._
@@ -27,6 +26,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
private val treatedClassInfos = perRunCaches.newMap[Symbol, Type]()
+ /** Map a lazy, mixedin field accessor to it's trait member accessor */
+ private val initializer = perRunCaches.newMap[Symbol, Symbol]
+
+ /** Deferred bitmaps that will be added during the transformation of a class */
+ private val deferredBitmaps = perRunCaches.newMap[Symbol, List[Tree]]() withDefaultValue Nil
+
// --------- helper functions -----------------------------------------------
/** A member of a trait is implemented statically if its implementation after the
@@ -40,10 +45,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - field accessors and superaccessors, except for lazy value accessors which become initializer
* methods in the impl class (because they can have arbitrary initializers)
*/
- private def isImplementedStatically(sym: Symbol) =
- sym.owner.isImplClass && sym.isMethod &&
- (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED)) &&
- (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isLazy)
+ private def isImplementedStatically(sym: Symbol) = (
+ sym.owner.isImplClass
+ && sym.isMethod
+ && (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED))
+ && (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isLazy)
+ )
/** A member of a trait is static only if it belongs only to the
* implementation class, not the interface, and it is implemented
@@ -66,6 +73,30 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
private def toInterface(tp: Type): Type =
atPhase(currentRun.mixinPhase)(tp.typeSymbol.toInterface).tpe
+ private def isFieldWithBitmap(field: Symbol) = {
+ field.info // ensure that nested objects are transformed
+ // For checkinit consider normal value getters
+ // but for lazy values only take into account lazy getters
+ field.isLazy && field.isMethod && !field.isDeferred
+ }
+
+ /** Does this field require an initialized bit?
+ * Note: fields of classes inheriting DelayedInit are not checked.
+ * This is because the they are neither initialized in the constructor
+ * nor do they have a setter (not if they are vals anyway). The usual
+ * logic for setting bitmaps does therefor not work for such fields.
+ * That's why they are excluded.
+ */
+ private def needsInitFlag(sym: Symbol) = (
+ settings.checkInit.value
+ && sym.isGetter
+ && !sym.isInitializedToDefault
+ && !sym.hasFlag(PARAMACCESSOR | SPECIALIZED | LAZY)
+ && !sym.accessed.hasFlag(PRESUPER)
+ && !sym.isOuterAccessor
+ && !(sym.owner isSubClass DelayedInitClass)
+ )
+
/** Maps all parts of this type that refer to implementation classes to
* their corresponding interfaces.
*/
@@ -132,8 +163,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
def addMember(clazz: Symbol, member: Symbol): Symbol = {
debuglog("new member of " + clazz + ":" + member.defString)
- clazz.info.decls enter member
- member.setFlag(MIXEDIN)
+ clazz.info.decls enter member setFlag MIXEDIN
}
def needsExpandedSetterName(field: Symbol) = !field.isLazy && (
@@ -202,12 +232,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
}
- /** Map a lazy, mixedin field accessor to it's trait member accessor */
- val initializer = perRunCaches.newMap[Symbol, Symbol]
-
- /** Deferred bitmaps that will be added during the transformation of a class */
- val deferredBitmaps = perRunCaches.newMap[Symbol, List[Tree]]()
-
/** Add all members to be mixed in into a (non-trait-) class
* These are:
* for every mixin trait T that is not also inherited by the superclass:
@@ -221,7 +245,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
def addMixedinMembers(clazz: Symbol, unit : CompilationUnit) {
def cloneBeforeErasure(iface: Symbol, clazz: Symbol, imember: Symbol): Symbol = {
- val newSym = atPhase(currentRun.erasurePhase){
+ val newSym = atPhase(currentRun.erasurePhase) {
val res = imember.cloneSymbol(clazz)
// since we used the member (imember) from the interface that represents the trait that's being mixed in,
// have to instantiate the interface type params (that may occur in imember's info) as they are seen from the class
@@ -257,6 +281,10 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
"%s (%s) is not a an implementation class, it cannot mix in %s".format(
impl, impl.defaultFlagString, iface)
)
+ if (!impl.isImplClass) {
+ debugwarn("!!! " + impl + " has an impl class name, but !isImplClass: " + impl.defaultFlagString + ", mixing in " + iface)
+ }
+
for (member <- impl.info.decls) {
if (isForwarded(member)) {
val imember = member.overriddenSymbol(iface)
@@ -355,10 +383,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - The parents of every class are mapped from implementation class to interface
* - Implementation classes become modules that inherit nothing
* and that define all.
- *
- * @param sym ...
- * @param tp ...
- * @return ...
*/
override def transformInfo(sym: Symbol, tp: Type): Type = tp match {
case ClassInfoType(parents, decls, clazz) =>
@@ -403,8 +427,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
tp
}
- import scala.collection._
-
/** Return a map of single-use fields to the lazy value that uses them during initialization.
* Each field has to be private and defined in the enclosing class, and there must
* be exactly one lazy value using it.
@@ -455,7 +477,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
class MixinTransformer(unit : CompilationUnit) extends Transformer {
/** Within a static implementation method: the parameter referring to the
- * current object undefined everywhere else.
+ * current object. Undefined everywhere else.
*/
private var self: Symbol = _
@@ -466,11 +488,10 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** The typer */
private var localTyper: erasure.Typer = _
private def typedPos(pos: Position)(tree: Tree) = localTyper typed { atPos(pos)(tree) }
+ private def localTyped(pos: Position, tree: Tree, pt: Type) = localTyper.typed(atPos(pos)(tree), pt)
/** Map lazy values to the fields they should null after initialization. */
- private var lazyValNullables: mutable.MultiMap[Symbol, Symbol] = _
-
- import scala.collection._
+ private var lazyValNullables: Map[Symbol, Set[Symbol]] = _
/** Map a field symbol to a unique integer denoting its position in the class layout.
* For each class, fields defined by the class come after inherited fields. Mixed-in
@@ -539,8 +560,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
/** Create an identifier which references self parameter.
- *
- * @param pos ...
*/
private def selfRef(pos: Position) =
gen.mkAttributedIdent(self) setPos pos
@@ -571,21 +590,44 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* form <code>M.sym</code> where M is the symbol's implementation module.
*/
private def staticRef(sym: Symbol): Tree = {
- sym.owner.info //todo: needed?
- sym.owner.owner.info //todo: needed?
- if (sym.owner.sourceModule == NoSymbol)
- assert(false, "" + sym + " in " + sym.owner + " in " + sym.owner.owner +
- " " + sym.owner.owner.info.decls)//debug
+ sym.owner.info //todo: needed?
+ sym.owner.owner.info //todo: needed?
+
+ assert(
+ sym.owner.sourceModule ne NoSymbol,
+ "" + sym.fullLocationString + " in " + sym.owner.owner + " " + sym.owner.owner.info.decls
+ )
REF(sym.owner.sourceModule) DOT sym
}
- @inline private def bitmapOperation[T](field: Symbol, transientCase: => T, privateCase: => T, rest: => T): T =
- if (field.accessed.hasAnnotation(TransientAttr))
- transientCase
- else if (field.hasFlag(PRIVATE | notPRIVATE))
- privateCase
- else
- rest
+ def needsInitAndHasOffset(sym: Symbol) =
+ needsInitFlag(sym) && (fieldOffset contains sym)
+
+ /** Examines the symbol and returns a name indicating what brand of
+ * bitmap it requires. The possibilities are the BITMAP_* vals
+ * defined in StdNames. If it needs no bitmap, nme.NO_NAME.
+ */
+ def bitmapCategory(field: Symbol): Name = {
+ import nme._
+ val isNormal = (
+ if (isFieldWithBitmap(field)) true
+ // bitmaps for checkinit fields are not inherited
+ else if (needsInitFlag(field) && !field.isDeferred) false
+ else return NO_NAME
+ )
+ if (field.accessed hasAnnotation TransientAttr) {
+ if (isNormal) BITMAP_TRANSIENT
+ else BITMAP_CHECKINIT_TRANSIENT
+ }
+ else if (field hasFlag PRIVATE | notPRIVATE) {
+ if (isNormal) BITMAP_PRIVATE
+ else BITMAP_CHECKINIT
+ }
+ else {
+ if (isNormal) BITMAP_NORMAL
+ else BITMAP_CHECKINIT
+ }
+ }
/** Add all new definitions to a non-trait class
* These fall into the following categories:
@@ -604,7 +646,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* @param clazz The class to which definitions are added
*/
private def addNewDefs(clazz: Symbol, stats: List[Tree]): List[Tree] = {
- val newDefs = new ListBuffer[Tree]
+ val newDefs = mutable.ListBuffer[Tree]()
/** Attribute given tree and anchor at given position */
def attributedDef(pos: Position, tree: Tree): Tree = {
@@ -613,7 +655,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
/** The position of given symbol, or, if this is undefined,
- * the position of the current class. */
+ * the position of the current class.
+ */
def position(sym: Symbol) =
if (sym.pos == NoPosition) clazz.pos else sym.pos
@@ -624,13 +667,11 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** Add new method definition.
*
- * @param sym The method
- * @param rhs A function that maps formal parameters to the method's
- * right-hand side
+ * @param sym The method symbol.
+ * @param rhs The method body.
*/
- def addDefDef(sym: Symbol, rhs: List[Symbol] => Tree) {
- addDef(position(sym), DefDef(sym, rhs(sym.paramss.head)))
- }
+ def addDefDef(sym: Symbol, rhs: Tree = EmptyTree) = addDef(position(sym), DefDef(sym, rhs))
+ def addValDef(sym: Symbol, rhs: Tree = EmptyTree) = addDef(position(sym), ValDef(sym, rhs))
/** Add `newdefs` to `stats`, removing any abstract method definitions
* in <code>stats</code> that are matched by some symbol defined in
@@ -647,12 +688,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
true
}
if (newDefs.isEmpty) stats
- else newDefs ::: stats.filter(isNotDuplicate)
+ else newDefs ::: (stats filter isNotDuplicate)
}
def addDeferredBitmap(clazz: Symbol, tree: Tree) {
- // Append the set of deffered defs
- deferredBitmaps(clazz) = typedPos(clazz.pos)(tree)::deferredBitmaps.getOrElse(clazz, List())
+ // Append the set of deferred defs
+ deferredBitmaps(clazz) ::= typedPos(clazz.pos)(tree)
}
/** If `stat` is a superaccessor, complete it by adding a right-hand side.
@@ -663,13 +704,13 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* This rhs is typed and then mixin transformed.
*/
def completeSuperAccessor(stat: Tree) = stat match {
- case DefDef(mods, name, tparams, List(vparams), tpt, EmptyTree)
- if (stat.symbol.isSuperAccessor) =>
+ case DefDef(mods, name, tparams, List(vparams), tpt, EmptyTree) if stat.symbol.isSuperAccessor =>
val rhs0 = (Super(clazz, tpnme.EMPTY) DOT stat.symbol.alias)(vparams map (v => Ident(v.symbol)): _*)
- val rhs1 = localTyper.typed(atPos(stat.pos)(rhs0), stat.symbol.tpe.resultType)
+ val rhs1 = localTyped(stat.pos, rhs0, stat.symbol.tpe.resultType)
val rhs2 = atPhase(currentRun.mixinPhase)(transform(rhs1))
- debuglog("complete super acc " + stat.symbol + stat.symbol.locationString +
- " " + rhs1 + " " + stat.symbol.alias + stat.symbol.alias.locationString +
+
+ debuglog("complete super acc " + stat.symbol.fullLocationString +
+ " " + rhs1 + " " + stat.symbol.alias.fullLocationString +
"/" + stat.symbol.alias.owner.hasFlag(lateINTERFACE))//debug
treeCopy.DefDef(stat, mods, name, tparams, List(vparams), tpt, rhs2)
case _ =>
@@ -683,38 +724,35 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* unlike public or protected vals, which can use inherited bitmaps.
* Similarly fields in the checkinit mode use private bitmaps.
*/
- def localBitmapField(field: Symbol) =
- field.accessed.hasAnnotation(TransientAttr) || field.hasFlag(PRIVATE | notPRIVATE) || checkinitField(field)
+ def isLocalBitmapField(field: Symbol) = (
+ field.accessed.hasAnnotation(TransientAttr)
+ || field.hasFlag(PRIVATE | notPRIVATE)
+ || isCheckInitField(field)
+ )
/**
* Return the bitmap field for 'offset'. Depending on the hierarchy it is possible to reuse
* the bitmap of its parents. If that does not exist yet we create one.
*/
- def bitmapFor(clazz0: Symbol, offset: Int, field: Symbol, searchParents:Boolean = true): Symbol = {
- def bitmapLazyName: Name =
- bitmapOperation(field, nme.bitmapNameForTransient(offset / FLAGS_PER_WORD),
- nme.bitmapNameForPrivate(offset / FLAGS_PER_WORD),
- nme.bitmapName(offset / FLAGS_PER_WORD))
- def bitmapCheckinitName: Name =
- bitmapOperation(field, nme.bitmapNameForCheckinitTransient(offset / FLAGS_PER_WORD),
- nme.bitmapNameForCheckinit(offset / FLAGS_PER_WORD),
- nme.bitmapNameForCheckinit(offset / FLAGS_PER_WORD))
- val checkinitField = !field.isLazy
- val bitmapName = if (checkinitField) bitmapCheckinitName else bitmapLazyName
+ def bitmapFor(clazz0: Symbol, offset: Int, field: Symbol, searchParents: Boolean = true): Symbol = {
+ val category = bitmapCategory(field)
+ val bitmapName = nme.newBitmapName(category, offset / FLAGS_PER_WORD)
+ val sym = clazz0.info.member(bitmapName)
+
+ assert(!sym.isOverloaded, sym)
def createBitmap: Symbol = {
- val sym = clazz0.newVariable(clazz0.pos, bitmapName).setInfo(IntClass.tpe)
- atPhase(currentRun.typerPhase) {
- sym addAnnotation VolatileAttr
- }
+ val sym = clazz0.newVariable(clazz0.pos, bitmapName) setInfo IntClass.tpe
+ atPhase(currentRun.typerPhase)(sym addAnnotation VolatileAttr)
- // What's going on here, why is setFlag called three times?
- bitmapOperation(
- field,
- { sym.addAnnotation(TransientAttr); sym.setFlag(PrivateLocal) },
- sym setFlag PrivateLocal,
- sym setFlag (if (checkinitField) PrivateLocal else PROTECTED)
- )
+ category match {
+ case nme.BITMAP_TRANSIENT | nme.BITMAP_CHECKINIT_TRANSIENT => sym addAnnotation TransientAttr
+ case _ =>
+ }
+ category match {
+ case nme.BITMAP_NORMAL if field.isLazy => sym setFlag PROTECTED
+ case _ => sym setFlag PrivateLocal
+ }
clazz0.info.decls.enter(sym)
if (clazz0 == clazz)
@@ -729,43 +767,35 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
sym
}
- var sym = clazz0.info.member(bitmapName)
- assert(!sym.hasFlag(OVERLOADED))
- if (sym == NoSymbol) {
- if (searchParents && !localBitmapField(field))
- bitmapForParents(clazz0, offset, field) match {
- case Some(bitmap) =>
- sym = bitmap
- case None =>
- sym = createBitmap
- }
- else
- sym = createBitmap
- }
- sym
+
+ if (sym ne NoSymbol)
+ sym
+ else if (searchParents && !isLocalBitmapField(field))
+ bitmapForParents(clazz0, offset, field) getOrElse createBitmap
+ else
+ createBitmap
}
def bitmapForParents(clazz0: Symbol, offset: Int, valSym: Symbol): Option[Symbol] = {
def requiredBitmaps(fs: Int): Int = if (fs == 0) -1 else (fs - 1) / FLAGS_PER_WORD
-
- var res:Option[Symbol] = None
val bitmapNum = offset / FLAGS_PER_WORD
-
// filter private and transient
// since we do not inherit normal values (in checkinit mode) also filter them out
- for (cl <- clazz0.info.baseClasses.tail.filter(c => !c.isTrait && !c.hasFlag(JAVA))
- if res == None) {
+ // !!! Not sure how that comment relates to this code...
+ superClassesToCheck(clazz0) foreach { cl =>
val fields0 = usedBits(cl)
if (requiredBitmaps(fields0) < bitmapNum) {
- val fields1 = cl.info.decls.filter(decl => fieldWithBitmap(decl) && !localBitmapField(decl)).size
- if (requiredBitmaps(fields0 + fields1) >= bitmapNum)
- res = Some(bitmapFor(cl, offset, valSym, false))
- else return None // Don't waste time, since we won't find bitmap anyway
+ val fields1 = cl.info.decls filter isNonLocalFieldWithBitmap size;
+ return {
+ if (requiredBitmaps(fields0 + fields1) >= bitmapNum)
+ Some(bitmapFor(cl, offset, valSym, false))
+ else None // Don't waste time, since we won't find bitmap anyway
+ }
}
}
- res
+ None
}
/** Return an (untyped) tree of the form 'Clazz.this.bmp = Clazz.this.bmp | mask'. */
@@ -813,15 +843,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* the 'n' is (offset / 32), the MASK is (1 << (offset % 32)).
*/
def mkLazyDef(clazz: Symbol, lzyVal: Symbol, init: List[Tree], retVal: Tree, offset: Int): Tree = {
- def nullify(sym: Symbol): Tree = {
- val sym1 = if (sym.hasAccessorFlag) sym.accessed else sym
- Select(This(clazz), sym1) === LIT(null)
- }
+ def nullify(sym: Symbol) = Select(This(clazz), sym.accessedOrSelf) === LIT(null)
val bitmapSym = bitmapFor(clazz, offset, lzyVal)
val mask = LIT(1 << (offset % FLAGS_PER_WORD))
def cond = mkTest(clazz, mask, bitmapSym, true)
- val nulls = (lazyValNullables(lzyVal).toList sortBy (_.id) map nullify)
+ val nulls = lazyValNullables(lzyVal).toList sortBy (_.id) map nullify
def syncBody = init ::: List(mkSetFlag(clazz, offset, lzyVal), UNIT)
log("nulling fields inside " + lzyVal + ": " + nulls)
@@ -833,8 +860,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
rhs match {
case Block(List(assign), returnTree) =>
val Assign(moduleVarRef, _) = assign
- val cond = Apply(Select(moduleVarRef, nme.eq),List(Literal(Constant(null))))
- val doubleSynchrTree = gen.mkDoubleCheckedLocking(attrThis, cond, List(assign), Nil)
+ val cond = Apply(Select(moduleVarRef, nme.eq), List(NULL))
+ val doubleSynchrTree = gen.mkDoubleCheckedLocking(attrThis, cond, List(assign), Nil)
Block(List(doubleSynchrTree), returnTree)
case _ =>
assert(false, "Invalid getter " + rhs + " for module in class " + clazz)
@@ -853,261 +880,222 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
typedPos(pos)(BLOCK(result, retVal))
}
- /** Complete lazy field accessors. Applies only to classes, for it's own (non inherited) lazy fields.
- * If 'checkinit' is enabled, getters that check for the initialized bit are generated, and
- * the class constructor is changed to set the initialized bits.
+ /** Complete lazy field accessors. Applies only to classes,
+ * for it's own (non inherited) lazy fields. If 'checkinit'
+ * is enabled, getters that check for the initialized bit are
+ * generated, and the class constructor is changed to set the
+ * initialized bits.
*/
def addCheckedGetters(clazz: Symbol, stats: List[Tree]): List[Tree] = {
-
- val stats1 = for (stat <- stats; sym = stat.symbol) yield stat match {
- case DefDef(mods, name, tp, vp, tpt, rhs)
- if sym.isLazy && rhs != EmptyTree && !clazz.isImplClass =>
- assert(fieldOffset.isDefinedAt(sym))
- val rhs1 = if (sym.tpe.resultType.typeSymbol == UnitClass)
+ def dd(stat: DefDef) = {
+ val DefDef(mods, name, tp, vp, tpt, rhs) = stat
+ val sym = stat.symbol
+ def isUnit = sym.tpe.resultType.typeSymbol == UnitClass
+ def isEmpty = rhs == EmptyTree
+
+ if (sym.isLazy && !isEmpty && !clazz.isImplClass) {
+ assert(fieldOffset contains sym, sym)
+ treeCopy.DefDef(stat, mods, name, tp, vp, tpt,
+ if (isUnit)
mkLazyDef(clazz, sym, List(rhs), UNIT, fieldOffset(sym))
else {
val Block(stats, res) = rhs
mkLazyDef(clazz, sym, stats, Select(This(clazz), res.symbol), fieldOffset(sym))
}
- treeCopy.DefDef(stat, mods, name, tp, vp, tpt, rhs1)
-
- case DefDef(mods, name, tp, vp, tpt, rhs)
- if needsInitFlag(sym) && rhs != EmptyTree && !clazz.isImplClass && !clazz.isTrait =>
- assert(fieldOffset.isDefinedAt(sym))
- val rhs1 = (mkCheckedAccessor(clazz, _: Tree, fieldOffset(sym), stat.pos, sym))(
- if (sym.tpe.resultType.typeSymbol == UnitClass) UNIT else rhs
+ )
+ }
+ else if (needsInitFlag(sym) && !isEmpty && !clazz.hasFlag(IMPLCLASS | TRAIT)) {
+ assert(fieldOffset contains sym, sym)
+ treeCopy.DefDef(stat, mods, name, tp, vp, tpt,
+ (mkCheckedAccessor(clazz, _: Tree, fieldOffset(sym), stat.pos, sym))(
+ if (sym.tpe.resultType.typeSymbol == UnitClass) UNIT
+ else rhs
)
- treeCopy.DefDef(stat, mods, name, tp, vp, tpt, rhs1)
-
- case DefDef(mods, name, tp, vp, tpt, rhs) if sym.isConstructor =>
+ )
+ }
+ else if (sym.isConstructor) {
treeCopy.DefDef(stat, mods, name, tp, vp, tpt, addInitBits(clazz, rhs))
-
- case DefDef(mods, name, tp, vp, tpt, rhs)
- if settings.checkInit.value && !clazz.isTrait && sym.isSetter =>
- val getter = sym.getter(clazz)
- if (needsInitFlag(getter) && fieldOffset.isDefinedAt(getter))
- treeCopy.DefDef(stat, mods, name, tp, vp, tpt,
- Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter))), UNIT))
- else
- stat
- case DefDef(mods, name, tp, vp, tpt, rhs)
- if sym.isModule && (!clazz.isTrait || clazz.isImplClass) && !sym.hasFlag(BRIDGE) =>
- val attrThis =
- if (clazz.isImplClass) {
- gen.mkAttributedIdent(vp.head.head.symbol)
- // Martin to Hubert I think this can be replaced by selfRef(tree.pos)
- } else
- gen.mkAttributedThis(clazz)
- val rhs1 = mkInnerClassAccessorDoubleChecked(attrThis, rhs)
- treeCopy.DefDef(stat, mods, name, tp, vp, tpt, typedPos(stat.pos)(rhs1))
- case _ => stat
+ }
+ else if (settings.checkInit.value && !clazz.isTrait && sym.isSetter) {
+ val getter = sym.getter(clazz)
+ if (needsInitFlag(getter) && fieldOffset.isDefinedAt(getter))
+ treeCopy.DefDef(stat, mods, name, tp, vp, tpt,
+ Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter))), UNIT)
+ )
+ else stat
+ }
+ else if (sym.isModule && (!clazz.isTrait || clazz.isImplClass) && !sym.isBridge) {
+ treeCopy.DefDef(stat, mods, name, tp, vp, tpt,
+ typedPos(stat.pos) {
+ mkInnerClassAccessorDoubleChecked(
+ // Martin to Hubert: I think this can be replaced by selfRef(tree.pos)
+ // @PP: It does not seem so, it crashes for me trying to bootstrap.
+ if (clazz.isImplClass) gen.mkAttributedIdent(vp.head.head.symbol) else gen.mkAttributedThis(clazz),
+ rhs
+ )
+ }
+ )
+ }
+ else stat
+ }
+ stats map {
+ case defn: DefDef => dd(defn)
+ case stat => stat
}
- stats1
}
- /** Does this field require an initialized bit?
- * Note: fields of classes inheriting DelayedInit are not checked.
- * This is because the they are neither initialized in the constructor
- * nor do they have a setter (not if they are vals anyway). The usual
- * logic for setting bitmaps does therefor not work for such fields.
- * That's why they are excluded.
- */
- def needsInitFlag(sym: Symbol) = {
- val res = (settings.checkInit.value
- && sym.isGetter
- && !sym.isInitializedToDefault
- && !sym.hasFlag(PARAMACCESSOR | SPECIALIZED | LAZY)
- && !sym.accessed.hasFlag(PRESUPER)
- && !sym.isOuterAccessor
- && !(sym.owner isSubClass DelayedInitClass))
-
-// if (settings.debug.value) {
-// log("needsInitFlag(" + sym.fullName + "): " + res)
-// log("\tsym.isGetter: " + sym.isGetter)
-// log("\t!isInitializedToDefault: " + !sym.isInitializedToDefault + sym.hasFlag(DEFAULTINIT) + sym.hasAccessorFlag + sym.isTerm)
-// log("\t!sym.isParamAccessor: " + !sym.isParamAccessor)
-// //println("\t!sym.accessed.hasFlag(PRESUPER): " + !sym.accessed.hasFlag(PRESUPER))
-// log("\t!sym.isOuterAccessor: " + !sym.isOuterAccessor)
-// }
-
- res
+ class AddInitBitsTransformer(clazz: Symbol) extends Transformer {
+ private def checkedGetter(lhs: Tree) = {
+ val sym = clazz.info decl lhs.symbol.getterName suchThat (_.isGetter)
+ if (needsInitAndHasOffset(sym)) {
+ log("adding checked getter for: " + sym + " " + lhs.symbol.defaultFlagString)
+ List(localTyper typed mkSetFlag(clazz, fieldOffset(sym), sym))
+ }
+ else Nil
+ }
+ override def transformStats(stats: List[Tree], exprOwner: Symbol) = {
+ // !!! Ident(self) is never referenced, is it supposed to be confirming
+ // that self is anything in particular?
+ super.transformStats(
+ stats flatMap {
+ case stat @ Assign(lhs @ Select(This(_), _), rhs) => stat :: checkedGetter(lhs)
+ // remove initialization for default values
+ case Apply(lhs @ Select(Ident(self), _), List(EmptyTree)) if lhs.symbol.isSetter => Nil
+ case stat => List(stat)
+ },
+ exprOwner
+ )
+ }
}
/** Adds statements to set the 'init' bit for each field initialized
- * in the body of a constructor.
+ * in the body of a constructor.
*/
- def addInitBits(clazz: Symbol, rhs: Tree): Tree = {
- new Transformer {
- override def transformStats(stats: List[Tree], exprOwner: Symbol) = {
- val stats1 = stats flatMap { stat => stat match {
- case Assign(lhs @ Select(This(_), _), rhs) =>
- val sym = clazz.info.decl(nme.getterName(lhs.symbol.name))
- .suchThat(_.isGetter)
- if (rhs == EmptyTree)
- List()
- else if (sym != NoSymbol && needsInitFlag(sym) && fieldOffset.isDefinedAt(sym)) {
- log("adding checked getter for: " + sym + " " + Flags.flagsToString(lhs.symbol.flags))
- List(stat, localTyper.typed(mkSetFlag(clazz, fieldOffset(sym), sym)))
- } else {
- List(stat)
- }
- case Apply(setter @ Select(Ident(self), _), List(EmptyTree)) if setter.symbol.isSetter =>
- // remove initialization for default values
- List()
- case _ => List(stat)
- }
- }
- super.transformStats(stats1, exprOwner)
- }
- }.transform(rhs)
- }
+ def addInitBits(clazz: Symbol, rhs: Tree): Tree =
+ new AddInitBitsTransformer(clazz) transform rhs
- def fieldWithBitmap(field: Symbol) = {
- field.info // ensure that nested objects are transformed
- // For checkinit consider normal value getters
- // but for lazy values only take into account lazy getters
- field.isLazy && field.isMethod && !field.isDeferred
- }
+ def isNonLocalFieldWithBitmap(field: Symbol) =
+ isFieldWithBitmap(field) && !isLocalBitmapField(field)
- def checkinitField(field: Symbol) =
+ def isCheckInitField(field: Symbol) =
needsInitFlag(field) && !field.isDeferred
+ def superClassesToCheck(clazz: Symbol) =
+ clazz.ancestors filterNot (_ hasFlag TRAIT | JAVA)
+
/**
* Return the number of bits used by superclass fields.
*/
- def usedBits(clazz0: Symbol): Int = {
- def needsBitmap(field: Symbol) = field.owner != clazz0 && fieldWithBitmap(field)
- var bits = 0
- for {
- cl <- clazz0.info.baseClasses.tail
- if !cl.isTrait && !cl.hasFlag(JAVA)
- field <- cl.info.decls.iterator
- if needsBitmap(field) && !localBitmapField(field)
- } bits += 1
-
- bits
- }
+ def usedBits(clazz0: Symbol): Int =
+ superClassesToCheck(clazz0) flatMap (_.info.decls) count { f =>
+ f.owner != clazz0 && isNonLocalFieldWithBitmap(f)
+ }
+
+ // begin addNewDefs
/** Fill the map from fields to offset numbers.
* Instead of field symbols, the map keeps their getter symbols. This makes
* code generation easier later.
*/
- def buildFieldPositions(clazz0: Symbol) {
- var fields = usedBits(clazz0)
- var fieldsPrivate = 0
- var fieldsTransient = 0
- var fieldsCheckinit = 0
- var fieldsCheckinitTransient = 0
-
- for (f <- clazz0.info.decls.iterator) {
- debuglog(f.fullName + " -> " + fields)
-
- if (fieldWithBitmap(f)) {
- val (idx, _) =
- bitmapOperation(f, (fieldsTransient, fieldsTransient += 1),
- (fieldsPrivate, fieldsPrivate += 1),
- (fields, fields += 1))
- fieldOffset(f) = idx
- } else if (checkinitField(f)) {
- // bitmaps for checkinit fields are not inherited
- val (idx, _) =
- bitmapOperation(f, (fieldsCheckinitTransient, fieldsCheckinitTransient += 1),
- (fieldsCheckinit, fieldsCheckinit += 1),
- (fieldsCheckinit, fieldsCheckinit += 1))
+ def buildBitmapOffsets() {
+ def fold(zero: Int, fields: List[Symbol]) = {
+ var idx = zero
+ fields foreach { f =>
+ idx += 1
fieldOffset(f) = idx
}
}
+ clazz.info.decls.toList groupBy bitmapCategory foreach {
+ case (nme.NO_NAME, _) => ()
+ case (nme.BITMAP_NORMAL, fields) => fold(usedBits(clazz), fields)
+ case (_, fields) => fold(0, fields)
+ }
}
-
- // begin addNewDefs
- buildFieldPositions(clazz)
+ buildBitmapOffsets()
var stats1 = addCheckedGetters(clazz, stats)
- // add deffered bitmaps
- deferredBitmaps.remove(clazz) match {
- case Some(deferred) =>
- stats1 = add(stats1, deferred)
- case None =>
+ // add deferred bitmaps
+ deferredBitmaps remove clazz foreach { d => stats1 = add(stats1, d) }
+
+ def accessedReference(sym: Symbol) = sym.tpe match {
+ case MethodType(Nil, ConstantType(c)) => Literal(c)
+ case _ =>
+ // if it is a mixed-in lazy value, complete the accessor
+ if (sym.isLazy && sym.isGetter) {
+ val isUnit = sym.tpe.resultType.typeSymbol == UnitClass
+ val initCall = Apply(staticRef(initializer(sym)), gen.mkAttributedThis(clazz) :: Nil)
+ val selection = Select(This(clazz), sym.accessed)
+ val init = if (isUnit) initCall else atPos(sym.pos)(Assign(selection, initCall))
+ val returns = if (isUnit) UNIT else selection
+
+ mkLazyDef(clazz, sym, List(init), returns, fieldOffset(sym))
+ }
+ else sym.getter(sym.owner).tpe.resultType.typeSymbol match {
+ case UnitClass => UNIT
+ case _ => Select(This(clazz), sym.accessed)
+ }
}
+ def isOverriddenSetter(sym: Symbol) =
+ nme.isTraitSetterName(sym.name) && {
+ val other = sym.nextOverriddenSymbol
+ isOverriddenAccessor(other.getter(other.owner), clazz.info.baseClasses)
+ }
// for all symbols `sym` in the class definition, which are mixed in:
- for (sym <- clazz.info.decls) {
- if (sym hasFlag MIXEDIN) {
- if (clazz hasFlag lateINTERFACE) {
- // if current class is a trait interface, add an abstract method for accessor `sym`
- addDefDef(sym, vparamss => EmptyTree)
- } else if (!clazz.isTrait) {
- // if class is not a trait add accessor definitions
- if ((sym hasFlag ACCESSOR) &&
- (!(sym hasFlag DEFERRED) || (sym hasFlag lateDEFERRED))) {
- // add accessor definitions
- addDefDef(sym, vparams => {
- val accessedRef = sym.tpe match {
- case MethodType(List(), ConstantType(c)) => Literal(c)
+ for (sym <- clazz.info.decls ; if sym hasFlag MIXEDIN) {
+ // if current class is a trait interface, add an abstract method for accessor `sym`
+ if (clazz hasFlag lateINTERFACE) {
+ addDefDef(sym)
+ }
+ // if class is not a trait add accessor definitions
+ else if (!clazz.isTrait) {
+ if (sym.hasAccessorFlag && (!sym.isDeferred || sym.hasFlag(lateDEFERRED))) {
+ // add accessor definitions
+ addDefDef(sym, {
+ val accessedRef = accessedReference(sym)
+ if (sym.isSetter) {
+ if (isOverriddenSetter(sym)) UNIT
+ else accessedRef match {
+ case Literal(_) => accessedRef
case _ =>
- // if it is a mixed-in lazy value, complete the accessor
- if (sym.isLazy && sym.isGetter) {
- val rhs1 =
- if (sym.tpe.resultType.typeSymbol == UnitClass)
- mkLazyDef(clazz, sym, List(Apply(staticRef(initializer(sym)), List(gen.mkAttributedThis(clazz)))), UNIT, fieldOffset(sym))
- else {
- val assign = atPos(sym.pos) {
- Assign(Select(This(sym.accessed.owner), sym.accessed) /*gen.mkAttributedRef(sym.accessed)*/ ,
- Apply(staticRef(initializer(sym)), gen.mkAttributedThis(clazz) :: Nil))
- }
- mkLazyDef(clazz, sym, List(assign), Select(This(clazz), sym.accessed), fieldOffset(sym))
- }
- rhs1
- } else if (sym.getter(sym.owner).tpe.resultType.typeSymbol == UnitClass) {
- UNIT
- } else {
- Select(This(clazz), sym.accessed)
- }
+ val init = Assign(accessedRef, Ident(sym.paramss.head.head))
+ val getter = sym.getter(clazz)
+
+ if (!needsInitFlag(getter)) init
+ else Block(init, mkSetFlag(clazz, fieldOffset(getter), getter), UNIT)
}
- if (sym.isSetter) {
- val isOverriddenSetter =
- nme.isTraitSetterName(sym.name) && {
- val other = sym.nextOverriddenSymbol
- (other != NoSymbol) && isOverriddenAccessor(other.getter(other.owner), clazz.info.baseClasses)
- }
- if (isOverriddenSetter) UNIT
- else accessedRef match {
- case Literal(_) => accessedRef
- case _ =>
- val init = Assign(accessedRef, Ident(vparams.head))
- val getter = sym.getter(clazz)
- if (needsInitFlag(getter))
- Block(List(init, mkSetFlag(clazz, fieldOffset(getter), getter)), UNIT)
- else
- init
- }
- } else if (needsInitFlag(sym)) {
- mkCheckedAccessor(clazz, accessedRef, fieldOffset(sym), sym.pos, sym)
- } else
- gen.mkCheckInit(accessedRef)
- })
- } else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) {
- // add modules
- val vdef = gen.mkModuleVarDef(sym)
- addDef(position(sym), vdef)
-
- val rhs = gen.newModule(sym, vdef.symbol.tpe)
- val assignAndRet = gen.mkAssignAndReturn(vdef.symbol, rhs)
- val attrThis = gen.mkAttributedThis(clazz)
- val rhs1 = mkInnerClassAccessorDoubleChecked(attrThis, assignAndRet)
- addDef(position(sym), DefDef(sym, rhs1))
- } else if (!sym.isMethod) {
- // add fields
- addDef(position(sym), ValDef(sym))
- } else if (sym.isSuperAccessor) {
- // add superaccessors
- addDefDef(sym, vparams => EmptyTree)
- } else {
- // add forwarders
- assert(sym.alias != NoSymbol, sym)
- addDefDef(sym, vparams =>
- Apply(staticRef(sym.alias), gen.mkAttributedThis(clazz) :: (vparams map Ident)))
- }
+ }
+ else if (needsInitFlag(sym))
+ mkCheckedAccessor(clazz, accessedRef, fieldOffset(sym), sym.pos, sym)
+ else
+ gen.mkCheckInit(accessedRef)
+ })
+ }
+ else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) {
+ // add modules
+ val vdef = gen.mkModuleVarDef(sym)
+ addDef(position(sym), vdef)
+
+ val rhs = gen.newModule(sym, vdef.symbol.tpe)
+ val assignAndRet = gen.mkAssignAndReturn(vdef.symbol, rhs)
+ val attrThis = gen.mkAttributedThis(clazz)
+ val rhs1 = mkInnerClassAccessorDoubleChecked(attrThis, assignAndRet)
+
+ addDefDef(sym, rhs1)
+ }
+ else if (!sym.isMethod) {
+ // add fields
+ addValDef(sym)
+ }
+ else if (sym.isSuperAccessor) {
+ // add superaccessors
+ addDefDef(sym)
+ }
+ else {
+ // add forwarders
+ assert(sym.alias != NoSymbol, sym)
+ // debuglog("New forwarder: " + sym.defString + " => " + sym.alias.defString)
+ addDefDef(sym, Apply(staticRef(sym.alias), gen.mkAttributedThis(clazz) :: sym.paramss.head.map(Ident)))
}
}
}
@@ -1116,20 +1104,18 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
stats1
}
- private def nullableFields(templ: Template) = {
- val nullables = new mutable.HashMap[Symbol, mutable.Set[Symbol]] with mutable.MultiMap[Symbol, Symbol] {
- override def default(key: Symbol) = mutable.Set.empty
- }
-
+ private def nullableFields(templ: Template): Map[Symbol, Set[Symbol]] = {
+ val scope = templ.symbol.owner.info.decls
// if there are no lazy fields, take the fast path and save a traversal of the whole AST
- if (templ.symbol.owner.info.decls.exists(_.isLazy)) {
+ if (scope exists (_.isLazy)) {
+ val map = mutable.Map[Symbol, Set[Symbol]]() withDefaultValue Set()
// check what fields can be nulled for
- val uses = singleUseFields(templ)
- for ((field, users) <- uses; lazyFld <- users) {
- nullables.addBinding(lazyFld, field)
- }
+ for ((field, users) <- singleUseFields(templ); lazyFld <- users)
+ map(lazyFld) += field
+
+ map.toMap
}
- nullables
+ else Map()
}
/** The transform that gets applied to a tree after it has been completely
@@ -1145,31 +1131,27 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - change super calls to methods in implementation classes to static calls
* (@see staticCall)
* - change `this` in implementation modules to references to the self parameter
- * - refer to fields in some implementation class vie an abstract method in the interface.
+ * - refer to fields in some implementation class via an abstract method in the interface.
*/
private def postTransform(tree: Tree): Tree = {
val sym = tree.symbol
// change every node type that refers to an implementation class to its
// corresponding interface, unless the node's symbol is an implementation class.
- if (tree.tpe.typeSymbol.isImplClass &&
- ((tree.symbol eq null) || !tree.symbol.isImplClass))
- tree.tpe = toInterface(tree.tpe);
+ if (tree.tpe.typeSymbol.isImplClass && ((sym eq null) || !sym.isImplClass))
+ tree.tpe = toInterface(tree.tpe)
tree match {
case Template(parents, self, body) =>
// change parents of templates to conform to parents in the symbol info
val parents1 = currentOwner.info.parents map (t => TypeTree(t) setPos tree.pos)
-
- lazyValNullables = nullableFields(tree.asInstanceOf[Template])
+ // mark fields which can be nulled afterward
+ lazyValNullables = nullableFields(tree.asInstanceOf[Template]) withDefaultValue Set()
// add all new definitions to current class or interface
- val body1 = addNewDefs(currentOwner, body)
-
- treeCopy.Template(tree, parents1, self, body1)
+ treeCopy.Template(tree, parents1, self, addNewDefs(currentOwner, body))
- case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
- if (tree.symbol == Object_asInstanceOf && (qual.tpe <:< targ.tpe)) =>
- // remove widening casts
+ // remove widening casts
+ case Apply(TypeApply(Select(qual, _), targ :: _), _) if isCastSymbol(sym) && (qual.tpe <:< targ.tpe) =>
qual
case Apply(Select(qual, _), args) =>
@@ -1183,16 +1165,20 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - if qual == super, and we are not in an implementation class, `this`
*/
def staticCall(target: Symbol) = {
- if (target == NoSymbol)
- assert(false, "" + sym + ":" + sym.tpe + " " + sym.owner + " " + implClass(sym.owner) + " " + implClass(sym.owner).info.member(sym.name) + " " + atPhase(phase.prev)(implClass(sym.owner).info.member(sym.name).tpe) + " " + phase);//debug
-
+ def implSym = implClass(sym.owner).info.member(sym.name)
+ assert(target ne NoSymbol,
+ List(sym + ":", sym.tpe, sym.owner, implClass(sym.owner), implSym,
+ atPhase(phase.prev)(implSym.tpe), phase) mkString " "
+ )
typedPos(tree.pos)(Apply(staticRef(target), transformSuper(qual) :: args))
}
+
if (isStaticOnly(sym)) {
// change calls to methods which are defined only in implementation
// classes to static calls of methods in implementation modules
staticCall(sym)
- } else qual match {
+ }
+ else qual match {
case Super(_, mix) =>
// change super calls to methods in implementation classes to static calls.
// Transform references super.m(args) as follows:
@@ -1203,14 +1189,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
assert(false, "illegal super in trait: " + currentOwner.enclClass + " " + tree);
if (sym.owner hasFlag lateINTERFACE) {
if (sym.hasAccessorFlag) {
- assert(args.isEmpty)
+ assert(args.isEmpty, args)
val sym1 = sym.overridingSymbol(currentOwner.enclClass)
typedPos(tree.pos)((transformSuper(qual) DOT sym1)())
} else {
staticCall(atPhase(phase.prev)(sym.overridingSymbol(implClass(sym.owner))))
}
} else {
- assert(!currentOwner.enclClass.isImplClass)
+ assert(!currentOwner.enclClass.isImplClass, currentOwner.enclClass)
tree
}
case _ =>
@@ -1225,12 +1211,11 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
case Select(qual, name) if sym.owner.isImplClass && !isStaticOnly(sym) =>
assert(!sym.isMethod, "no method allowed here: %s%s %s".format(sym, sym.isImplOnly, flagsToString(sym.flags)))
-
// refer to fields in some implementation class via an abstract
// getter in the interface.
- val iface = toInterface(sym.owner.tpe).typeSymbol
+ val iface = toInterface(sym.owner.tpe).typeSymbol
val getter = sym.getter(iface)
- assert(getter != NoSymbol)
+ assert(getter != NoSymbol, sym)
typedPos(tree.pos)((qual DOT getter)())
case Assign(Apply(lhs @ Select(qual, _), List()), rhs) =>
@@ -1241,7 +1226,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
needsExpandedSetterName(lhs.symbol)
) setPos lhs.pos
- typedPos(tree.pos) { (qual DOT setter)(rhs) }
+ typedPos(tree.pos)((qual DOT setter)(rhs))
case _ =>
tree
@@ -1253,19 +1238,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* when coming back, it performs a postTransform at phase after.
*/
override def transform(tree: Tree): Tree = {
- try { //debug
- val outerTyper = localTyper
- val tree1 = super.transform(preTransform(tree))
- val res = atPhase(phase.next)(postTransform(tree1))
- // needed when not flattening inner classes. parts after an
- // inner class will otherwise be typechecked with a wrong scope
- localTyper = outerTyper
- res
- } catch {
- case ex: Throwable =>
- if (settings.debug.value) Console.println("exception when traversing " + tree)
- throw ex
- }
+ val saved = localTyper
+ val tree1 = super.transform(preTransform(tree))
+ // localTyper needed when not flattening inner classes. parts after an
+ // inner class will otherwise be typechecked with a wrong scope
+ try atPhase(phase.next)(postTransform(tree1))
+ finally localTyper = saved
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 71e1fecbd7..f7a4a9fc30 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -933,26 +933,26 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match {
case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) =>
- log("Unify - basic case: " + tp1 + ", " + tp2)
+ debuglog("Unify - basic case: " + tp1 + ", " + tp2)
if (isValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1))
env + ((sym1, tp2))
else
if (strict) throw UnifyError else env
case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) =>
- log("Unify TypeRefs: " + tp1 + " and " + tp2 + " with args " + (args1, args2) + " - ")
+ debuglog("Unify TypeRefs: " + tp1 + " and " + tp2 + " with args " + (args1, args2) + " - ")
if (strict && args1.length != args2.length) throw UnifyError
val e = unify(args1, args2, env, strict)
- log("unified to: " + e)
+ debuglog("unified to: " + e)
e
case (TypeRef(_, sym1, _), _) if sym1.isTypeParameterOrSkolem =>
env
case (MethodType(params1, res1), MethodType(params2, res2)) =>
if (strict && params1.length != params2.length) throw UnifyError
- log("Unify MethodTypes: " + tp1 + " and " + tp2)
+ debuglog("Unify MethodTypes: " + tp1 + " and " + tp2)
unify(res1 :: (params1 map (_.tpe)), res2 :: (params2 map (_.tpe)), env, strict)
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
if (strict && tparams1.length != tparams2.length) throw UnifyError
- log("Unify PolyTypes: " + tp1 + " and " + tp2)
+ debuglog("Unify PolyTypes: " + tp1 + " and " + tp2)
unify(res1, res2, env, strict)
case (PolyType(_, res), other) =>
unify(res, other, env, strict)
@@ -965,7 +965,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case (AnnotatedType(_, tp1, _), tp2) => unify(tp2, tp1, env, strict)
case (ExistentialType(_, res1), _) => unify(tp2, res1, env, strict)
case _ =>
- log("don't know how to unify %s [%s] with %s [%s]".format(tp1, tp1.getClass, tp2, tp2.getClass))
+ debuglog("don't know how to unify %s [%s] with %s [%s]".format(tp1, tp1.getClass, tp2, tp2.getClass))
env
}
@@ -977,7 +977,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val nenv = unify(args._1, args._2, emptyEnv, strict)
if (env.keySet intersect nenv.keySet isEmpty) env ++ nenv
else {
- log("could not unify: u(" + args._1 + ", " + args._2 + ") yields " + nenv + ", env: " + env)
+ debuglog("could not unify: u(" + args._1 + ", " + args._2 + ") yields " + nenv + ", env: " + env)
throw UnifyError
}
}
@@ -1216,14 +1216,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
(treeType =:= memberType) || { // anyref specialization
memberType match {
case PolyType(_, resTpe) =>
- log("Conformance for anyref - polytype with result type: " + resTpe + " and " + treeType + "\nOrig. sym.: " + origSymbol)
+ debuglog("Conformance for anyref - polytype with result type: " + resTpe + " and " + treeType + "\nOrig. sym.: " + origSymbol)
try {
val e = unify(origSymbol.tpe, memberType, emptyEnv, true)
- log("obtained env: " + e)
+ debuglog("obtained env: " + e)
e.keySet == env.keySet
} catch {
case _ =>
- log("Could not unify.")
+ debuglog("Could not unify.")
false
}
case _ => false
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 31aaaa36b8..0beb01cc71 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -206,8 +206,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
case Select(Super(_, mix), name) =>
if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) {
- unit.error(tree.pos, "super may be not be used on "+
- (if (sym.hasAccessorFlag) sym.accessed else sym))
+ unit.error(tree.pos, "super may be not be used on "+ sym.accessedOrSelf)
}
else if (isDisallowed(sym)) {
unit.error(tree.pos, "super not allowed here: use this." + name.decode + " instead")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9a3516c29c..ba1a9d6bfd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2185,7 +2185,8 @@ trait Typers extends Modes with Adaptations {
* follow the logic, so I renamed one to something distinct.
*/
def accesses(looker: Symbol, accessed: Symbol) = accessed.hasLocalFlag && (
- accessed.isParamAccessor || (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
+ (accessed.isParamAccessor)
+ || (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
)
def checkNoDoubleDefsAndAddSynthetics(stats: List[Tree]): List[Tree] = {
diff --git a/test/pending/run/t2897.scala b/test/pending/run/t2897.scala
new file mode 100644
index 0000000000..40fd3c2b08
--- /dev/null
+++ b/test/pending/run/t2897.scala
@@ -0,0 +1,22 @@
+class A {
+ def f1(t: String) = {
+ trait T {
+ def xs = Nil map (_ => t)
+ }
+ }
+ def f2(t: String) = {
+ def xs = Nil map (_ => t)
+ }
+ def f3(t: String) = {
+ var t1 = 5
+ trait T {
+ def xs = { t1 = 10 ; t }
+ }
+ }
+ def f4() = {
+ var u = 5
+ trait T {
+ def xs = Nil map (_ => u = 10)
+ }
+ }
+}