@@ -55,6 +55,16 @@ 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
+ /** Determines whether the given information request should trigger the given symbol's completer.
59
+ * See comments to `Symbol.needsInitialize` for details.
60
+ */
61
+ protected def shouldTriggerCompleter (symbol : Symbol , completer : Type , isFlagRelated : Boolean , mask : Long ) =
62
+ completer match {
63
+ case null => false
64
+ case _ : FlagAgnosticCompleter => ! isFlagRelated
65
+ case _ => abort(s " unsupported completer: $completer of class ${if (completer != null ) completer.getClass else null } for symbol ${symbol.fullName}" )
66
+ }
67
+
58
68
/** The original owner of a class. Used by the backend to generate
59
69
* EnclosingMethod attributes.
60
70
*/
@@ -67,7 +77,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
67
77
def isParamWithDefault : Boolean = this .hasDefault
68
78
def isByNameParam : Boolean = this .isValueParameter && (this hasFlag BYNAMEPARAM )
69
79
def isImplementationArtifact : Boolean = (this hasFlag BRIDGE ) || (this hasFlag VBRIDGE ) || (this hasFlag ARTIFACT )
70
- def isJava : Boolean = this hasFlag JAVA
80
+ def isJava : Boolean = isJavaDefined
71
81
def isVal : Boolean = isTerm && ! isModule && ! isMethod && ! isMutable
72
82
def isVar : Boolean = isTerm && ! isModule && ! isMethod && isMutable
73
83
@@ -88,7 +98,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
88
98
def toTypeIn (site : Type ): Type = site.memberType(this )
89
99
def toTypeConstructor : Type = typeConstructor
90
100
def setTypeSignature (tpe : Type ): this .type = { setInfo(tpe); this }
91
- def getAnnotations : List [AnnotationInfo ] = { initialize; annotations }
92
101
def setAnnotations (annots : AnnotationInfo * ): this .type = { setAnnotations(annots.toList); this }
93
102
94
103
def getter : Symbol = getter(owner)
@@ -218,9 +227,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
218
227
val m = newModuleSymbol(clazz.name.toTermName, clazz.pos, MODULE | newFlags)
219
228
connectModuleToClass(m, clazz.asInstanceOf [ClassSymbol ])
220
229
}
221
- final def newModule (name : TermName , pos : Position = NoPosition , newFlags : Long = 0L ): ModuleSymbol = {
222
- val m = newModuleSymbol(name, pos, newFlags | MODULE )
223
- val clazz = newModuleClass(name.toTypeName, pos, m getFlag ModuleToClassFlags )
230
+ final def newModule (name : TermName , pos : Position = NoPosition , newFlags0 : Long = 0L ): ModuleSymbol = {
231
+ val newFlags = newFlags0 | MODULE
232
+ val m = newModuleSymbol(name, pos, newFlags)
233
+ val clazz = newModuleClass(name.toTypeName, pos, newFlags & ModuleToClassFlags )
224
234
connectModuleToClass(m, clazz)
225
235
}
226
236
@@ -238,9 +248,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
238
248
final def newModuleSymbol (name : TermName , pos : Position = NoPosition , newFlags : Long = 0L ): ModuleSymbol =
239
249
newTermSymbol(name, pos, newFlags).asInstanceOf [ModuleSymbol ]
240
250
241
- final def newModuleAndClassSymbol (name : Name , pos : Position , flags : FlagSet ): (ModuleSymbol , ClassSymbol ) = {
242
- val m = newModuleSymbol(name, pos, flags | MODULE )
243
- val c = newModuleClass(name.toTypeName, pos, m getFlag ModuleToClassFlags )
251
+ final def newModuleAndClassSymbol (name : Name , pos : Position , flags0 : FlagSet ): (ModuleSymbol , ClassSymbol ) = {
252
+ val flags = flags0 | MODULE
253
+ val m = newModuleSymbol(name, pos, flags)
254
+ val c = newModuleClass(name.toTypeName, pos, flags & ModuleToClassFlags )
244
255
connectModuleToClass(m, c)
245
256
(m, c)
246
257
}
@@ -489,14 +500,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
489
500
def isAliasType = false
490
501
def isAbstractType = false
491
502
def isSkolem = false
492
- def isMacro = this hasFlag MACRO
493
503
494
504
/** A Type, but not a Class. */
495
505
def isNonClassType = false
496
506
497
507
/** The bottom classes are Nothing and Null, found in Definitions. */
498
508
def isBottomClass = false
499
- def isSpecialized = this hasFlag SPECIALIZED
500
509
501
510
/** These are all tests for varieties of ClassSymbol, which has these subclasses:
502
511
* - ModuleClassSymbol
@@ -585,11 +594,20 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
585
594
&& owner.isPackageClass
586
595
&& nme.isReplWrapperName(name)
587
596
)
588
- final def getFlag (mask : Long ): Long = flags & mask
597
+ final def getFlag (mask : Long ): Long = {
598
+ if (! isCompilerUniverse && needsInitialize(isFlagRelated = true , mask = mask)) initialize
599
+ flags & mask
600
+ }
589
601
/** Does symbol have ANY flag in `mask` set? */
590
- final def hasFlag (mask : Long ): Boolean = (flags & mask) != 0
602
+ final def hasFlag (mask : Long ): Boolean = {
603
+ if (! isCompilerUniverse && needsInitialize(isFlagRelated = true , mask = mask)) initialize
604
+ (flags & mask) != 0
605
+ }
591
606
/** Does symbol have ALL the flags in `mask` set? */
592
- final def hasAllFlags (mask : Long ): Boolean = (flags & mask) == mask
607
+ final def hasAllFlags (mask : Long ): Boolean = {
608
+ if (! isCompilerUniverse && needsInitialize(isFlagRelated = true , mask = mask)) initialize
609
+ (flags & mask) == mask
610
+ }
593
611
594
612
def setFlag (mask : Long ): this .type = { _rawflags |= mask ; this }
595
613
def resetFlag (mask : Long ): this .type = { _rawflags &= ~ mask ; this }
@@ -1138,7 +1156,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
1138
1156
/** See comment in HasFlags for how privateWithin combines with flags.
1139
1157
*/
1140
1158
private [this ] var _privateWithin : Symbol = _
1141
- def privateWithin = _privateWithin
1159
+ def privateWithin = {
1160
+ if (! isCompilerUniverse && needsInitialize(isFlagRelated = false , mask = 0 )) initialize
1161
+ _privateWithin
1162
+ }
1142
1163
def privateWithin_= (sym : Symbol ) { _privateWithin = sym }
1143
1164
def setPrivateWithin (sym : Symbol ): this .type = { privateWithin_=(sym) ; this }
1144
1165
@@ -1329,6 +1350,46 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
1329
1350
this
1330
1351
}
1331
1352
1353
+ /** Called when the programmer requests information that might require initialization of the underlying symbol.
1354
+ *
1355
+ * `isFlagRelated` and `mask` describe the nature of this information.
1356
+ * isFlagRelated = true means that the programmer needs particular bits in flags.
1357
+ * isFlagRelated = false means that the request is unrelated to flags (annotations or privateWithin).
1358
+ *
1359
+ * In our current architecture, symbols for top-level classes and modules
1360
+ * are created as dummies. Package symbols just call newClass(name) or newModule(name) and
1361
+ * consider their job done.
1362
+ *
1363
+ * In order for such a dummy to provide meaningful info (e.g. a list of its members),
1364
+ * it needs to go through unpickling. Unpickling is a process of reading Scala metadata
1365
+ * from ScalaSignature annotations and assigning it to symbols and types.
1366
+ *
1367
+ * A single unpickling session takes a top-level class or module, parses the ScalaSignature annotation
1368
+ * and then reads metadata for the unpicklee, its companion (if any) and all their members recursively
1369
+ * (i.e. the pickle not only contains info about directly nested classes/modules, but also about
1370
+ * classes/modules nested into those and so on).
1371
+ *
1372
+ * Unpickling is triggered automatically whenever typeSignature (info in compiler parlance) is called.
1373
+ * This happens because package symbols assign completer thunks to the dummies they create.
1374
+ * Therefore metadata loading happens lazily and transparently.
1375
+ *
1376
+ * Almost transparently. Unfortunately metadata isn't limited to just signatures (i.e. lists of members).
1377
+ * It also includes flags (which determine e.g. whether a class is sealed or not), annotations and privateWithin.
1378
+ * This gives rise to unpleasant effects like in SI-6277, when a flag test called on an uninitialize symbol
1379
+ * produces incorrect results.
1380
+ *
1381
+ * One might think that the solution is simple: automatically call the completer whenever one needs
1382
+ * flags, annotations and privateWithin - just like it's done for typeSignature. Unfortunately, this
1383
+ * leads to weird crashes in scalac, and currently we can't attempt to fix the core of the compiler
1384
+ * risk stability a few weeks before the final release.
1385
+ *
1386
+ * However we do need to fix this for runtime reflection, since it's not something we'd like to
1387
+ * expose to reflection users. Therefore a proposed solution is to check whether we're in a
1388
+ * runtime reflection universe and if yes then to commence initialization.
1389
+ */
1390
+ protected def needsInitialize (isFlagRelated : Boolean , mask : Long ) =
1391
+ ! isInitialized && (flags & LOCKED ) == 0 && shouldTriggerCompleter(this , if (infos ne null ) infos.info else null , isFlagRelated, mask)
1392
+
1332
1393
/** Was symbol's type updated during given phase? */
1333
1394
final def isUpdatedAt (pid : Phase # Id ): Boolean = {
1334
1395
assert(isCompilerUniverse)
@@ -1491,8 +1552,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
1491
1552
/** After the typer phase (before, look at the definition's Modifiers), contains
1492
1553
* the annotations attached to member a definition (class, method, type, field).
1493
1554
*/
1494
- def annotations : List [AnnotationInfo ] =
1555
+ def annotations : List [AnnotationInfo ] = {
1556
+ if (! isCompilerUniverse && needsInitialize(isFlagRelated = false , mask = 0 )) initialize
1495
1557
_annotations
1558
+ }
1496
1559
1497
1560
def setAnnotations (annots : List [AnnotationInfo ]): this .type = {
1498
1561
_annotations = annots
0 commit comments