summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorHubert Plociniczak <hubert.plociniczak@epfl.ch>2010-09-22 14:00:35 +0000
committerHubert Plociniczak <hubert.plociniczak@epfl.ch>2010-09-22 14:00:35 +0000
commita5d47fb693d9b88ea9ed414762f16e027be64ada (patch)
treec6c5962343a7c7a4e1c7d98dcc6b2ad930c91344 /src/compiler/scala/tools/nsc
parent39a8b1042e04a5b838ac5688e014c29680bf0561 (diff)
downloadscala-a5d47fb693d9b88ea9ed414762f16e027be64ada.tar.gz
scala-a5d47fb693d9b88ea9ed414762f16e027be64ada.tar.bz2
scala-a5d47fb693d9b88ea9ed414762f16e027be64ada.zip
Closes #1591.
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala28
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala76
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala9
8 files changed, 89 insertions, 52 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index a886e7468f..611780e776 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -259,30 +259,18 @@ abstract class TreeGen {
)
}
- // var m$: T = null; or, if class member: local var m$: T = _;
- /*!!!
- def mkModuleValDef(accessor: Symbol) = {
- val mval = accessor.owner.newValue(accessor.pos.focus, nme.moduleVarName(accessor.name))
+ def mkModuleVarDef(accessor: Symbol) = {
+ val mval = accessor.owner.newVariable(accessor.pos.focus, nme.moduleVarName(accessor.name))
.setInfo(accessor.tpe.finalResultType)
- .setFlag(LAZY);
+ .setFlag(LAZY)
+ .setFlag(MODULEVAR)
+ mval.setLazyAccessor(accessor)
if (mval.owner.isClass) {
mval setFlag (PRIVATE | LOCAL | SYNTHETIC)
mval.owner.info.decls.enter(mval)
}
- ValDef(mval, New(TypeTree(mval.tpe), List(List())))
- }
- */
-
- // var m$: T = null; or, if class member: local var m$: T = _;
- def mkModuleVarDef(accessor: Symbol) = {
- val mvar = accessor.owner.newVariable(accessor.pos.focus, nme.moduleVarName(accessor.name))
- .setInfo(accessor.tpe.finalResultType)
- .setFlag(MODULEVAR);
- if (mvar.owner.isClass) {
- mvar setFlag (PRIVATE | LOCAL | SYNTHETIC)
- mvar.owner.info.decls.enter(mvar)
- }
- ValDef(mvar, if (mvar.owner.isClass) EmptyTree else Literal(Constant(null)))
+ ValDef(mval, EmptyTree)
+ //ValDef(mval, newModule(accessor, mval.tpe))
}
// def m: T = { if (m$ eq null) m$ = new m$class(...) m$ }
@@ -295,7 +283,7 @@ abstract class TreeGen {
def mkModuleAccessDef(accessor: Symbol, tpe: Type) =
DefDef(accessor, newModule(accessor, tpe))
- private def newModule(accessor: Symbol, tpe: Type) =
+ def newModule(accessor: Symbol, tpe: Type) =
New(TypeTree(tpe),
List(for (pt <- tpe.typeSymbol.primaryConstructor.info.paramTypes)
yield This(accessor.owner.enclClass)))
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index aa47441a1a..bcd1ac0627 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -89,7 +89,6 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable =>
val LOCAL_SUFFIX = newTermName(LOCAL_SUFFIX_STRING)
val SETTER_SUFFIX = encode("_=")
val IMPL_CLASS_SUFFIX = newTermName("$class")
- val MODULE_SUFFIX = newTermName("$module")
val LOCALDUMMY_PREFIX = newTermName(LOCALDUMMY_PREFIX_STRING)
val SELECTOR_DUMMY = newTermName("<unapply-selector>")
@@ -175,9 +174,6 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable =>
def interfaceName(implname: Name): Name =
implname.subName(0, implname.length - IMPL_CLASS_SUFFIX.length)
- def moduleVarName(name: Name): Name =
- newTermName(name.toString() + MODULE_SUFFIX)
-
def superName(name: Name) = newTermName("super$" + name)
val PROTECTED_PREFIX = "protected$"
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index deffa1d852..cced26a780 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -3764,7 +3764,10 @@ A type's typeSymbol should never be inspected directly.
object adaptToNewRunMap extends TypeMap {
private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = {
if (sym.isModuleClass && !phase.flatClasses) {
- adaptToNewRun(pre, sym.sourceModule).moduleClass
+ if (!sym.owner.isPackageClass)
+ sym // Nested lazy object
+ else
+ adaptToNewRun(pre, sym.sourceModule).moduleClass
} else if ((pre eq NoPrefix) || (pre eq NoType) || sym.owner.isPackageClass) {
sym
} else {
@@ -4641,7 +4644,7 @@ A type's typeSymbol should never be inspected directly.
def specializesSym(tp: Type, sym: Symbol): Boolean =
tp.typeSymbol == NothingClass ||
tp.typeSymbol == NullClass && (sym.owner isSubClass ObjectClass) ||
- (tp.nonPrivateMember(sym.name).alternatives exists
+ (tp.member(sym.name).alternatives exists
(alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym)))
/** Does member `sym1' of `tp1' have a stronger type
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
index 1bee37bfe6..96c050b51f 100644
--- a/src/compiler/scala/tools/nsc/transform/Flatten.scala
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -48,7 +48,9 @@ abstract class Flatten extends InfoTransform {
for (sym <- decls.toList) {
if (sym.isTerm && !sym.isStaticModule) {
decls1 enter sym
- if (sym.isModule) sym.moduleClass setFlag LIFTED
+ if (sym.isModule) sym.moduleClass setFlag LIFTED // Only top modules
+ // Nested modules (MODULE flag is reset so we access through lazy):
+ if (sym.isModuleVar && sym.hasFlag(LAZY)) sym.lazyAccessor.lazyAccessor setFlag LIFTED
} else if (sym.isClass) {
liftClass(sym)
if (sym.needsImplClass) liftClass(erasure.implClass(sym))
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 72914934cb..7791cc0b02 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -156,7 +156,7 @@ abstract class LambdaLift extends InfoTransform {
}
changedFreeVars = true
if (settings.debug.value) log("" + sym + " is free in " + owner);
- if (sym.isVariable && !(sym hasFlag CAPTURED)) {
+ if ((sym.isVariable || (sym.isValue && sym.hasFlag(LAZY))) && !(sym hasFlag CAPTURED)) {
sym setFlag CAPTURED
val symClass = sym.tpe.typeSymbol;
atPhase(phase.next) {
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 92c92796cf..9c562dba86 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -383,7 +383,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* Each field has to be private and defined in the enclosing class, and there must
* be exactly one lazy value using it.
*
- * Such fields will be nulled after the initializer has memoized the lazy value.
+ * Such fields will be nulled after the initializer has memorized the lazy value.
*/
def singleUseFields(templ: Template): collection.Map[Symbol, List[Symbol]] = {
val usedIn = new mutable.HashMap[Symbol, List[Symbol]] {
@@ -402,6 +402,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
&& !(currentOwner.isGetter && currentOwner.accessed == sym) // getter
&& !definitions.isValueClass(sym.tpe.resultType.typeSymbol)
&& sym.owner == templ.symbol.owner
+ && !sym.hasFlag(LAZY)
&& !tree.isDef) {
log("added use in: " + currentOwner + " -- " + tree)
usedIn(sym) ::= currentOwner
@@ -429,7 +430,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 evrywhere else.
+ * current object undefined everywhere else.
*/
private var self: Symbol = _
@@ -719,6 +720,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* the class constructor is changed to set the initialized bits.
*/
def addCheckedGetters(clazz: Symbol, stats: List[Tree]): List[Tree] = {
+ // TODO: not used?
def findLazyAssignment(stats: List[Tree]): Tree = (
for (s @ Assign(lhs, _) <- stats ; if lhs.symbol hasFlag LAZY) yield s
) head // if there's no assignment then it's a bug and we crash
@@ -905,11 +907,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
} else
gen.mkCheckInit(accessedRef)
})
- } else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) {
- // add modules
- val vdef = gen.mkModuleVarDef(sym)
- addDef(position(sym), vdef)
- addDef(position(sym), gen.mkCachedModuleAccessDef(sym, vdef.symbol))
} else if (!sym.isMethod) {
// add fields
addDef(position(sym), ValDef(sym))
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 5c90a69c94..3044e61f2f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -51,11 +51,23 @@ abstract class RefChecks extends InfoTransform {
new RefCheckTransformer(unit)
override def changesBaseClasses = false
- def transformInfo(sym: Symbol, tp: Type): Type =
+ def transformInfo(sym: Symbol, tp: Type): Type = {
+ def isNestedModule = sym.isModule && !sym.isRoot && !sym.owner.isPackageClass
+
if (sym.isModule && !sym.isStatic) {
+
sym setFlag (lateMETHOD | STABLE)
+ if (isNestedModule) {
+ val moduleVar = sym.owner.info.decl(nme.moduleVarName(sym.name))
+ if (moduleVar == NoSymbol) {
+ gen.mkModuleVarDef(sym).symbol.setInfo(tp)
+ sym.resetFlag(MODULE)
+ sym.setFlag(LAZY | ACCESSOR)
+ }
+ }
PolyType(List(), tp)
} else tp
+ }
val toJavaRepeatedParam = new TypeMap {
def apply(tp: Type) = tp match {
@@ -908,11 +920,12 @@ abstract class RefChecks extends InfoTransform {
def transformStat(tree: Tree, index: Int): List[Tree] = tree match {
case ModuleDef(mods, name, impl) =>
val sym = tree.symbol
- val cdef = ClassDef(mods | MODULE, name, List(), impl)
- .setPos(tree.pos)
- .setSymbol(sym.moduleClass)
- .setType(NoType)
if (sym.isStatic) {
+ val cdef = ClassDef(mods | MODULE, name, List(), impl)
+ .setPos(tree.pos)
+ .setSymbol(sym.moduleClass)
+ .setType(NoType)
+
if (!sym.allOverriddenSymbols.isEmpty) {
val factory = sym.owner.newMethod(sym.pos, sym.name)
.setFlag(sym.flags | STABLE).resetFlag(MODULE)
@@ -929,17 +942,48 @@ abstract class RefChecks extends InfoTransform {
List(transform(cdef))
}
} else {
- val vdef = localTyper.typedPos(tree.pos) { gen.mkModuleVarDef(sym) }
- val ddef =
- atPhase(phase.next) {
- localTyper.typed {
- if (sym.owner.isTrait) gen.mkModuleAccessDcl(sym)
- else gen.mkCachedModuleAccessDef(sym, vdef.symbol)
+ def lazyNestedObjectTrees(transformedInfo: Boolean) = {
+ val cdef = ClassDef(mods | MODULE, name, List(), impl)
+ .setPos(tree.pos)
+ .setSymbol(if (!transformedInfo) sym.moduleClass else sym.lazyAccessor)
+ .setType(NoType)
+
+ val vdef = localTyper.typedPos(tree.pos){
+ if (!transformedInfo)
+ gen.mkModuleVarDef(sym)
+ else {
+ val vsym = sym.owner.info.decl(nme.moduleVarName(sym.name))
+ assert(vsym != NoSymbol, "Nested object after transformInfo set module variable")
+ ValDef(vsym, EmptyTree)
}
}
+ val vsym = vdef.symbol
- if (sym.owner.isTrait) transformTrees(List(cdef, ddef))
- else transformTrees(List(cdef, vdef, ddef))
+ val ddef = atPhase(phase.next) {
+ localTyper.typed {
+ val rhs = gen.newModule(sym, vsym.tpe)
+ if (!transformedInfo) {
+ sym.resetFlag(MODULE | FINAL | CASE)
+ sym.setFlag(LAZY | ACCESSOR | SYNTHETIC)
+
+ sym.setInfo(PolyType(List(), sym.tpe))
+ sym setFlag (lateMETHOD | STABLE)
+ }
+
+ val ownerTransformer = new ChangeOwnerTraverser(vsym, sym)
+ val lazyDef = atPos(tree.pos)(
+ DefDef(sym, ownerTransformer(
+ if (sym.owner.isTrait) rhs
+ else Block(List(
+ Assign(gen.mkAttributedRef(vsym), rhs)),
+ gen.mkAttributedRef(vsym)))
+ ))
+ lazyDef
+ }
+ }
+ transformTrees(List(cdef, vdef, ddef))
+ }
+ lazyNestedObjectTrees(sym.hasFlag(LAZY))
}
case ValDef(_, _, _, _) =>
@@ -963,11 +1007,11 @@ abstract class RefChecks extends InfoTransform {
if (hasUnitType)
typed(lazyDef) :: Nil
else
- typed(ValDef(vsym, EmptyTree)) :: typed(lazyDef) :: Nil
+ typed(ValDef(vsym, EmptyTree)) :: atPhase(phase.next) { typed(lazyDef) } :: Nil
} else {
- if (tree.symbol.isLocal && index <= currentLevel.maxindex && !tree.symbol.hasFlag(LAZY)) {
+ if (tree.symbol.isLocal && index <= currentLevel.maxindex) {
if (settings.debug.value) Console.println(currentLevel.refsym);
- unit.error(currentLevel.refpos, "forward reference extends over definition of " + tree.symbol);
+ unit.error(currentLevel.refpos, "forward reference extends over definition of " + tree.symbol)
}
List(tree1)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 52d79542c2..549e4d325f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -228,6 +228,13 @@ trait SyntheticMethods extends ast.TreeDSL {
result
}
+ def needsReadResolve =
+ // only nested objects inside objects should get readResolve automatically
+ // otherwise after de-serialization we get null references for lazy accessors (nested object -> lazy val + class def)
+ clazz.isSerializable &&
+ ((!clazz.owner.isPackageClass && clazz.owner.isModuleClass) || clazz.owner.isPackageClass)
+ //(clazz.companionClass != NoSymbol))
+
// A buffer collecting additional methods for the template body
val ts = new ListBuffer[Tree]
@@ -302,7 +309,7 @@ trait SyntheticMethods extends ast.TreeDSL {
* the readResolve() method (see http://www.javaworld.com/javaworld/
* jw-04-2003/jw-0425-designpatterns_p.html)
*/
- if (clazz.isSerializable && !hasReadResolve) {
+ if (!hasReadResolve && needsReadResolve){
// PP: To this day I really can't figure out what this next comment is getting at:
// the !!! normally means there is something broken, but if so, what is it?
//