Overhaul of mixin.

If extempore is going to fix the hard bugs then first he is going to
make them less hard to fix. The major work of interest in here is the
decomplification of the bitmap logic. Hopefully this will come in handy
for anyone wishing to try out other encodings.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25853 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
extempore 2011-10-19 20:23:13 +00:00
parent 7278b610e4
commit 1ae87317ab
11 changed files with 496 additions and 474 deletions

View File

@ -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)

View File

@ -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
)

View File

@ -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$"

View File

@ -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)

View File

@ -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)

View File

@ -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
}

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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")

View File

@ -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] = {

View File

@ -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)
}
}
}