@@ -55,23 +55,29 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
55
55
def newFreeTypeSymbol (name : TypeName , flags : Long = 0L , origin : String ): FreeTypeSymbol =
56
56
new FreeTypeSymbol (name, origin) initFlags flags
57
57
58
- /** The original owner of a class. Used by the backend to generate
59
- * EnclosingMethod attributes.
58
+ /**
59
+ * This map stores the original owner the the first time the owner of a symbol is re-assigned.
60
+ * The original owner of a symbol is needed in some places in the backend. Ideally, owners should
61
+ * be versioned like the type history.
60
62
*/
61
- val originalOwner = perRunCaches.newMap[Symbol , Symbol ]()
63
+ private val originalOwnerMap = perRunCaches.newMap[Symbol , Symbol ]()
62
64
63
65
// TODO - don't allow the owner to be changed without checking invariants, at least
64
66
// when under some flag. Define per-phase invariants for owner/owned relationships,
65
67
// e.g. after flatten all classes are owned by package classes, there are lots and
66
68
// lots of these to be declared (or more realistically, discovered.)
67
- protected def saveOriginalOwner (sym : Symbol ) {
68
- if (originalOwner contains sym) ()
69
- else originalOwner(sym) = sym.rawowner
69
+ protected def saveOriginalOwner (sym : Symbol ): Unit = {
70
+ // some synthetic symbols have NoSymbol as owner initially
71
+ if (sym.owner != NoSymbol ) {
72
+ if (originalOwnerMap contains sym) ()
73
+ else originalOwnerMap(sym) = sym.rawowner
74
+ }
70
75
}
76
+
71
77
protected def originalEnclosingMethod (sym : Symbol ): Symbol = {
72
78
if (sym.isMethod || sym == NoSymbol ) sym
73
79
else {
74
- val owner = originalOwner.getOrElse( sym, sym.rawowner)
80
+ val owner = sym.originalOwner
75
81
if (sym.isLocalDummy) owner.enclClass.primaryConstructor
76
82
else originalEnclosingMethod(owner)
77
83
}
@@ -757,8 +763,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
757
763
* So "isModuleNotMethod" exists not for its achievement in
758
764
* brevity, but to encapsulate the relevant condition.
759
765
*/
760
- def isModuleNotMethod = isModule && ! isMethod
761
- def isStaticModule = isModuleNotMethod && isStatic
766
+ def isModuleNotMethod = {
767
+ if (isModule) {
768
+ if (phase.refChecked) this .info // force completion to make sure lateMETHOD is there.
769
+ ! isMethod
770
+ } else false
771
+ }
772
+
773
+ // After RefChecks, the `isStatic` check is mostly redundant: all non-static modules should
774
+ // be methods (and vice versa). There's a corner case on the vice-versa with mixed-in module
775
+ // symbols:
776
+ // trait T { object A }
777
+ // object O extends T
778
+ // The module symbol A is cloned into T$impl (addInterfaces), and then cloned into O (mixin).
779
+ // Since the original A is not static, it's turned into a method. The clone in O however is
780
+ // static (owned by a module), but it's also a method.
781
+ def isStaticModule = isModuleNotMethod && isStatic
762
782
763
783
final def isInitializedToDefault = ! isType && hasAllFlags(DEFAULTINIT | ACCESSOR )
764
784
final def isThisSym = isTerm && owner.thisSym == this
@@ -909,10 +929,31 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
909
929
)
910
930
final def isModuleVar = hasFlag(MODULEVAR )
911
931
912
- /** Is this symbol static (i.e. with no outer instance)?
913
- * Q: When exactly is a sym marked as STATIC?
914
- * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep.
915
- * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
932
+ /**
933
+ * Is this symbol static (i.e. with no outer instance)?
934
+ * Q: When exactly is a sym marked as STATIC?
935
+ * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or
936
+ * any number of levels deep.
937
+ * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
938
+ *
939
+ * TODO: should this only be invoked on class / module symbols? because there's also `isStaticMember`.
940
+ *
941
+ * Note: the result of `isStatic` changes over time.
942
+ * - Lambdalift local definitions to the class level, the `owner` field is modified.
943
+ * object T { def foo { object O } }
944
+ * After lambdalift, the OModule.isStatic is true.
945
+ *
946
+ * - After flatten, nested classes are moved to the package level. Invoking `owner` on a
947
+ * class returns a package class, for which `isStaticOwner` is true. For example,
948
+ * class C { object O }
949
+ * OModuleClass.isStatic is true after flatten. Using phase travel to get before flatten,
950
+ * method `owner` returns the class C.
951
+ *
952
+ * Why not make a stable version of `isStatic`? Maybe some parts of the compiler depend on the
953
+ * current implementation. For example
954
+ * trait T { def foo = 1 }
955
+ * The method `foo` in the implementation class T$impl will be `isStatic`, because trait
956
+ * impl classes get the `lateMODULE` flag (T$impl.isStaticOwner is true).
916
957
*/
917
958
def isStatic = (this hasFlag STATIC ) || owner.isStaticOwner
918
959
@@ -1106,7 +1147,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
1106
1147
* - After lambdalift, all local method and class definitions (those not owned by a class
1107
1148
* or package class) change their owner to the enclosing class. This is done through
1108
1149
* a destructive "sym.owner = sym.owner.enclClass". The old owner is saved by
1109
- * saveOriginalOwner for the backend (needed to generate the EnclosingMethod attribute) .
1150
+ * saveOriginalOwner.
1110
1151
* - After flatten, all classes are owned by a PackageClass. This is done through a
1111
1152
* phase check (if after flatten) in the (overridden) method "def owner" in
1112
1153
* ModuleSymbol / ClassSymbol. The `rawowner` field is not modified.
@@ -1129,6 +1170,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
1129
1170
final def safeOwner : Symbol = if (this eq NoSymbol ) NoSymbol else owner
1130
1171
final def assertOwner : Symbol = if (this eq NoSymbol ) abort(" no-symbol does not have an owner" ) else owner
1131
1172
1173
+ /**
1174
+ * The initial owner of this symbol.
1175
+ */
1176
+ def originalOwner : Symbol = originalOwnerMap.getOrElse(this , rawowner)
1177
+
1132
1178
// TODO - don't allow the owner to be changed without checking invariants, at least
1133
1179
// when under some flag. Define per-phase invariants for owner/owned relationships,
1134
1180
// e.g. after flatten all classes are owned by package classes, there are lots and
@@ -1142,7 +1188,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
1142
1188
}
1143
1189
1144
1190
def ownerChain : List [Symbol ] = this :: owner.ownerChain
1145
- def originalOwnerChain : List [Symbol ] = this :: originalOwner.getOrElse(this , rawowner).originalOwnerChain
1146
1191
1147
1192
// Non-classes skip self and return rest of owner chain; overridden in ClassSymbol.
1148
1193
def enclClassChain : List [Symbol ] = owner.enclClassChain
0 commit comments