Skip to content

Commit 8b41f19

Browse files
committed
wip: modules during fields
class C { object o } trait T { object o } class MixedIn extends T abstract class AbsModAcc { def o: O ; class O } class ImplModAcc extends AbsModAcc { object o extends O } object top { object stat } class MethHolder { def m = { object local; local } }
1 parent f07a843 commit 8b41f19

File tree

7 files changed

+205
-211
lines changed

7 files changed

+205
-211
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
261261
private def memberClassesForInnerClassTable(classSymbol: Symbol): List[Symbol] = classSymbol.info.decls.collect({
262262
case sym if sym.isClass && !considerAsTopLevelImplementationArtifact(sym) =>
263263
sym
264-
case sym if sym.isModule && !considerAsTopLevelImplementationArtifact(sym) =>
264+
case sym if sym.isModuleNotMethod && !considerAsTopLevelImplementationArtifact(sym) =>
265265
val r = exitingPickler(sym.moduleClass)
266266
assert(r != NoSymbol, sym.fullLocationString)
267267
r

src/compiler/scala/tools/nsc/transform/Erasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ abstract class Erasure extends InfoTransform
492492
// If `member` is a ModuleSymbol, the bridge should not also be a ModuleSymbol. Otherwise we
493493
// end up with two module symbols with the same name in the same scope, which is surprising
494494
// when implementing later phases.
495-
if (member.isModule) newFlags = (newFlags | METHOD) & ~(MODULE | lateMETHOD | STABLE)
495+
if (member.isModule) newFlags = (newFlags | METHOD) & ~(MODULE | STABLE)
496496
val bridge = other.cloneSymbolImpl(root, newFlags) setPos root.pos
497497

498498
debuglog("generating bridge from %s (%s): %s to %s: %s".format(

src/compiler/scala/tools/nsc/transform/Fields.scala

Lines changed: 186 additions & 103 deletions
Large diffs are not rendered by default.

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 4 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import scala.tools.nsc.settings.ScalaVersion
1414
import scala.tools.nsc.settings.NoScalaVersion
1515

1616
import symtab.Flags._
17-
import transform.InfoTransform
17+
import transform.Transform
1818

1919

2020
/** <p>
@@ -43,7 +43,7 @@ import transform.InfoTransform
4343
*
4444
* @todo Check whether we always check type parameter bounds.
4545
*/
46-
abstract class RefChecks extends InfoTransform with scala.reflect.internal.transform.RefChecks {
46+
abstract class RefChecks extends Transform with scala.reflect.internal.transform.RefChecks {
4747

4848
val global: Global // need to repeat here because otherwise last mixin defines global as
4949
// SymbolTable. If we had DOT this would not be an issue
@@ -54,31 +54,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
5454

5555
/** the following two members override abstract members in Transform */
5656
val phaseName: String = "refchecks"
57-
override def phaseNewFlags: Long = lateMETHOD
5857

5958
def newTransformer(unit: CompilationUnit): RefCheckTransformer =
6059
new RefCheckTransformer(unit)
61-
override def changesBaseClasses = false
62-
63-
override def transformInfo(sym: Symbol, tp: Type): Type = {
64-
// !!! This is a sketchy way to do things.
65-
// It would be better to replace the module symbol with a method symbol
66-
// rather than creating this module/method hybrid which must be special
67-
// cased all over the place. Look for the call sites which use(d) some
68-
// variation of "isMethod && !isModule", which to an observer looks like
69-
// a nonsensical condition. (It is now "isModuleNotMethod".)
70-
if (sym.isModule && !sym.isStatic) {
71-
sym setFlag lateMETHOD | STABLE
72-
// Note that this as far as we can see it works equally well
73-
// to set the METHOD flag here and dump lateMETHOD, but it does
74-
// mean that under separate compilation the typer will see
75-
// modules as methods (albeit stable ones with singleton types.)
76-
// So for now lateMETHOD lives while we try to convince ourselves
77-
// we can live without it or deliver that info some other way.
78-
log(s"Stabilizing module method for ${sym.fullLocationString}")
79-
}
80-
super.transformInfo(sym, tp)
81-
}
8260

8361
val toJavaRepeatedParam = new SubstSymMap(RepeatedParamClass -> JavaRepeatedParamClass)
8462
val toScalaRepeatedParam = new SubstSymMap(JavaRepeatedParamClass -> RepeatedParamClass)
@@ -1180,69 +1158,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
11801158
finally popLevel()
11811159
}
11821160

1183-
/** Eliminate ModuleDefs. In all cases the ModuleDef (carrying a module symbol) is
1184-
* replaced with a ClassDef (carrying the corresponding module class symbol) with additional
1185-
* trees created as follows:
1186-
*
1187-
* 1) A statically reachable object (either top-level or nested only in objects) receives
1188-
* no additional trees.
1189-
* 2) An inner object which matches an existing member (e.g. implements an interface)
1190-
* receives an accessor DefDef to implement the interface.
1191-
* 3) An inner object otherwise receives a private ValDef which declares a module var
1192-
* (the field which holds the module class - it has a name like Foo$module) and an
1193-
* accessor for that field. The instance is created lazily, on first access.
1194-
*/
1195-
private def eliminateModuleDefs(moduleDef: Tree): List[Tree] = exitingRefchecks {
1196-
val ModuleDef(_, _, impl) = moduleDef
1197-
val module = moduleDef.symbol
1198-
val site = module.owner
1199-
val moduleName = module.name.toTermName
1200-
// The typer doesn't take kindly to seeing this ClassDef; we have to
1201-
// set NoType so it will be ignored.
1202-
val cdef = ClassDef(module.moduleClass, impl) setType NoType
1203-
1204-
def matchingInnerObject() = {
1205-
val newFlags = (module.flags | STABLE) & ~MODULE
1206-
val newInfo = NullaryMethodType(module.moduleClass.tpe)
1207-
val accessor = site.newMethod(moduleName, module.pos, newFlags) setInfoAndEnter newInfo
1208-
1209-
DefDef(accessor, Select(This(site), module)) :: Nil
1210-
}
1211-
val newTrees = cdef :: (
1212-
if (module.isStatic)
1213-
// trait T { def f: Object }; object O extends T { object f }. Need to generate method f in O.
1214-
if (module.isOverridingSymbol) matchingInnerObject() else Nil
1215-
else
1216-
newInnerObject(site, module)
1217-
)
1218-
transformTrees(newTrees map localTyper.typedPos(moduleDef.pos))
1219-
}
1220-
def newInnerObject(site: Symbol, module: Symbol): List[Tree] = {
1221-
if (site.isTrait)
1222-
DefDef(module, EmptyTree) :: Nil
1223-
else {
1224-
val moduleVar = site newModuleVarSymbol module
1225-
// used for the mixin case: need a new symbol owned by the subclass for the accessor, rather than repurposing the module symbol
1226-
def mkAccessorSymbol =
1227-
site.newMethod(module.name.toTermName, site.pos, STABLE | MODULE | MIXEDIN)
1228-
.setInfo(moduleVar.tpe)
1229-
.andAlso(self => if (module.isPrivate) self.expandName(module.owner))
1230-
1231-
val accessor = if (module.owner == site) module else mkAccessorSymbol
1232-
val accessorDef = DefDef(accessor, gen.mkAssignAndReturn(moduleVar, gen.newModule(module, moduleVar.tpe)).changeOwner(moduleVar -> accessor))
1233-
1234-
ValDef(moduleVar) :: accessorDef :: Nil
1235-
}
1236-
}
12371161

1238-
def mixinModuleDefs(clazz: Symbol): List[Tree] = {
1239-
val res = for {
1240-
mixinClass <- clazz.mixinClasses.iterator
1241-
module <- mixinClass.info.decls.iterator.filter(_.isModule)
1242-
newMember <- newInnerObject(clazz, module)
1243-
} yield transform(localTyper.typedPos(clazz.pos)(newMember))
1244-
res.toList
1245-
}
12461162

12471163
def transformStat(tree: Tree, index: Int): List[Tree] = tree match {
12481164
case t if treeInfo.isSelfConstrCall(t) =>
@@ -1253,7 +1169,6 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
12531169
debuglog("refsym = " + currentLevel.refsym)
12541170
reporter.error(currentLevel.refpos, "forward reference not allowed from self constructor invocation")
12551171
}
1256-
case ModuleDef(_, _, _) => eliminateModuleDefs(tree)
12571172
case ValDef(_, _, _, _) =>
12581173
val tree1 = transform(tree) // important to do before forward reference check
12591174
if (tree1.symbol.isLazy) tree1 :: Nil
@@ -1693,13 +1608,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
16931608
checkOverloadedRestrictions(currentOwner, currentOwner)
16941609
// SI-7870 default getters for constructors live in the companion module
16951610
checkOverloadedRestrictions(currentOwner, currentOwner.companionModule)
1696-
val bridges = addVarargBridges(currentOwner)
1697-
val moduleDesugared = if (currentOwner.isTrait) Nil else mixinModuleDefs(currentOwner)
1611+
val bridges = addVarargBridges(currentOwner) // TODO: do this during uncurry?
16981612
checkAllOverrides(currentOwner)
16991613
checkAnyValSubclass(currentOwner)
17001614
if (currentOwner.isDerivedValueClass)
17011615
currentOwner.primaryConstructor makeNotPrivate NoSymbol // SI-6601, must be done *after* pickler!
1702-
if (bridges.nonEmpty || moduleDesugared.nonEmpty) deriveTemplate(tree)(_ ::: bridges ::: moduleDesugared) else tree
1616+
if (bridges.nonEmpty) deriveTemplate(tree)(_ ::: bridges) else tree
17031617

17041618
case dc@TypeTreeWithDeferredRefCheck() => abort("adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc")
17051619
case tpt@TypeTree() =>

src/reflect/scala/reflect/internal/Phase.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ abstract class Phase(val prev: Phase) {
4747
final val specialized: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "specialize" || prev.specialized)
4848
final val refChecked: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "refchecks" || prev.refChecked)
4949

50-
// are we past the fields phase, so that we should allow writing to vals (as part of type checking trait setters)
50+
// are we past the fields phase, so that:
51+
// - we should allow writing to vals (as part of type checking trait setters)
52+
// - modules have module accessors
5153
final val assignsFields: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "fields" || prev.assignsFields)
5254

5355
/** This is used only in unsafeTypeParams, and at this writing is

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -324,17 +324,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
324324
final def newImport(pos: Position): TermSymbol =
325325
newTermSymbol(nme.IMPORT, pos)
326326

327-
def newModuleVarSymbol(accessor: Symbol): TermSymbol = {
328-
val newName = nme.moduleVarName(accessor.name.toTermName)
329-
val newFlags = MODULEVAR | ( if (this.isClass) PrivateLocal | SYNTHETIC else 0 )
330-
val newInfo = thisType.memberType(accessor).finalResultType
331-
val mval = newVariable(newName, accessor.pos.focus, newFlags.toLong) addAnnotation VolatileAttr
332-
333-
if (this.isClass)
334-
mval setInfoAndEnter newInfo
335-
else
336-
mval setInfo newInfo
337-
}
327+
def newModuleVarSymbol(accessor: Symbol): TermSymbol =
328+
newVariable(
329+
nme.moduleVarName(accessor.name.toTermName),
330+
accessor.pos.focus,
331+
(MODULEVAR | (if (isClass) PrivateLocal | SYNTHETIC else 0)).toLong) addAnnotation VolatileAttr
332+
338333

339334
final def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol =
340335
newTermSymbol(name, pos, newFlags).asInstanceOf[ModuleSymbol]
@@ -2771,7 +2766,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
27712766
override def isCapturedVariable = hasAllFlags(MUTABLE | CAPTURED) && !hasFlag(METHOD)
27722767

27732768
override def companionSymbol: Symbol = companionClass
2774-
override def moduleClass = if (isModule) referenced else NoSymbol
2769+
override def moduleClass = if (isModuleNotMethod) referenced else NoSymbol
27752770

27762771
override def isBridge = this hasFlag BRIDGE
27772772
override def isEarlyInitialized = this hasFlag PRESUPER

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3441,10 +3441,10 @@ trait Types
34413441
if (!sym.isOverridableMember || sym.owner == pre.typeSymbol) sym
34423442
else pre.nonPrivateMember(sym.name).suchThat { sym =>
34433443
// SI-7928 `isModuleNotMethod` is here to avoid crashing with spuriously "overloaded" module accessor and module symbols.
3444-
// These appear after refchecks eliminates ModuleDefs that implement an interface.
3444+
// These appear after the fields phase eliminates ModuleDefs that implement an interface.
34453445
// Here, we exclude the module symbol, which allows us to bind to the accessor.
3446-
// SI-8054 We must only do this after refchecks, otherwise we exclude the module symbol which does not yet have an accessor!
3447-
val isModuleWithAccessor = phase.refChecked && sym.isModuleNotMethod
3446+
// SI-8054 We must only do this after fields, otherwise we exclude the module symbol which does not yet have an accessor!
3447+
val isModuleWithAccessor = phase.assignsFields && sym.isModuleNotMethod
34483448
sym.isType || (!isModuleWithAccessor && sym.isStable && !sym.hasVolatileType)
34493449
} orElse sym
34503450
}

0 commit comments

Comments
 (0)