@@ -22,6 +22,7 @@ import config.Printers.pickling
22
22
class TreeUnpickler (reader : TastyReader , tastyName : TastyName .Table ) {
23
23
import TastyFormat ._
24
24
import TastyName ._
25
+ import TreeUnpickler ._
25
26
import tpd ._
26
27
27
28
private var readPositions = false
@@ -45,18 +46,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
45
46
private val treeAtAddr = new mutable.HashMap [Addr , Tree ]
46
47
private val typeAtAddr = new mutable.HashMap [Addr , Type ] // currently populated only for types that are known to be SHAREd.
47
48
48
- // Currently disabled set used for checking that all
49
- // already encountered symbols are forward refereneces. This
50
- // check fails in more complicated scenarios of separate
51
- // compilation in dotty (for instance: compile all of `core`
52
- // given the TASTY files of everything else in the compiler).
53
- // I did not have the time to track down what caused the failure.
54
- // The testing scheme could well have produced a false negative.
55
- //
56
- // private var stubs: Set[Symbol] = Set()
57
-
49
+ /** The root symbol denotation which are defined by the Tasty file associated with this
50
+ * TreeUnpickler. Set by `enterTopLevel`.
51
+ */
58
52
private var roots : Set [SymDenotation ] = null
59
53
54
+ /** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
60
55
private var ownerTree : OwnerTree = _
61
56
62
57
private def registerSym (addr : Addr , sym : Symbol ) = {
@@ -69,7 +64,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
69
64
*/
70
65
def enterTopLevel (roots : Set [SymDenotation ])(implicit ctx : Context ): Unit = {
71
66
this .roots = roots
72
- new TreeReader (reader).fork.indexStats(reader.endAddr)
67
+ var rdr = new TreeReader (reader).fork
68
+ ownerTree = new OwnerTree (NoAddr , 0 , rdr.fork, reader.endAddr)
69
+ rdr.indexStats(reader.endAddr)
73
70
}
74
71
75
72
/** The unpickled trees */
@@ -123,17 +120,19 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
123
120
/** Record all directly nested definitions and templates in current tree
124
121
* as `OwnerTree`s in `buf`
125
122
*/
126
- def scanTree (buf : ListBuffer [OwnerTree ]): Unit = {
123
+ def scanTree (buf : ListBuffer [OwnerTree ], mode : MemberDefMode = AllDefs ): Unit = {
127
124
val start = currentAddr
128
125
val tag = readByte()
129
- // println(s"scan tree at $currentAddr, tag = $tag")
130
126
tag match {
131
127
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | TEMPLATE =>
132
128
val end = readEnd()
133
129
for (i <- 0 until numRefs(tag)) readNat()
134
- buf += new OwnerTree (start, fork, end)
130
+ if (tag == TEMPLATE ) scanTrees(buf, end, MemberDefsOnly )
131
+ if (mode != NoMemberDefs ) buf += new OwnerTree (start, tag, fork, end)
132
+ goto(end)
135
133
case tag =>
136
- if (tag >= firstLengthTreeTag) {
134
+ if (mode == MemberDefsOnly ) skipTree(tag)
135
+ else if (tag >= firstLengthTreeTag) {
137
136
val end = readEnd()
138
137
var nrefs = numRefs(tag)
139
138
if (nrefs < 0 ) {
@@ -154,8 +153,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
154
153
/** Record all directly nested definitions and templates between current address and `end`
155
154
* as `OwnerTree`s in `buf`
156
155
*/
157
- def scanTrees (buf : ListBuffer [OwnerTree ], end : Addr ): Unit = {
158
- while (currentAddr.index < end.index) scanTree(buf)
156
+ def scanTrees (buf : ListBuffer [OwnerTree ], end : Addr , mode : MemberDefMode ): Unit = {
157
+ while (currentAddr.index < end.index) scanTree(buf, mode )
159
158
assert(currentAddr.index == end.index)
160
159
}
161
160
@@ -197,19 +196,25 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
197
196
until(end) { readNat(); readType().asInstanceOf [T ] }
198
197
199
198
/** Read referece to definition and return symbol created at that definition */
200
- def readSymRef ()(implicit ctx : Context ): Symbol = {
201
- val start = currentAddr
202
- val addr = readAddr()
203
- symAtAddr get addr match {
204
- case Some (sym) => sym
205
- case None =>
206
- // Create a stub; owner might be wrong but will be overwritten later.
207
- forkAt(addr).createSymbol()
208
- val sym = symAtAddr(addr)
209
- ctx.log(i " forward reference to $sym" )
210
- // stubs += sym
211
- sym
212
- }
199
+ def readSymRef ()(implicit ctx : Context ): Symbol = symbolAt(readAddr())
200
+
201
+ /** The symbol at given address; createa new one if none exists yet */
202
+ def symbolAt (addr : Addr )(implicit ctx : Context ): Symbol = symAtAddr.get(addr) match {
203
+ case Some (sym) =>
204
+ sym
205
+ case None =>
206
+ val sym = forkAt(addr).createSymbol()(ctx.withOwner(ownerTree.findOwner(addr)))
207
+ ctx.log(i " forward reference to $sym" )
208
+ sym
209
+ }
210
+
211
+ /** The symbol defined by current definition */
212
+ def symbolAtCurrent ()(implicit ctx : Context ): Symbol = symAtAddr.get(currentAddr) match {
213
+ case Some (sym) =>
214
+ assert(ctx.owner == sym.owner, i " owner discrepancy for $sym, expected: ${ctx.owner}, found: ${sym.owner}" )
215
+ sym
216
+ case None =>
217
+ createSymbol()
213
218
}
214
219
215
220
/** Read a type */
@@ -414,7 +419,21 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
414
419
/** Create symbol of definition node and enter in symAtAddr map
415
420
* @return the created symbol
416
421
*/
417
- def createSymbol ()(implicit ctx : Context ): Symbol = {
422
+ def createSymbol ()(implicit ctx : Context ): Symbol = nextByte match {
423
+ case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
424
+ createMemberSymbol()
425
+ case TEMPLATE =>
426
+ val localDummy = ctx.newLocalDummy(ctx.owner)
427
+ registerSym(currentAddr, localDummy)
428
+ localDummy
429
+ case tag =>
430
+ throw new Error (s " illegal createSymbol at $currentAddr, tag = $tag" )
431
+ }
432
+
433
+ /** Create symbol of member definition or parameter node and enter in symAtAddr map
434
+ * @return the created symbol
435
+ */
436
+ def createMemberSymbol ()(implicit ctx : Context ): Symbol = {
418
437
val start = currentAddr
419
438
val tag = readByte()
420
439
val end = readEnd()
@@ -451,29 +470,18 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
451
470
case _ =>
452
471
val completer = adjustIfModule(new Completer (subReader(start, end)))
453
472
if (isClass)
454
- ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer,
455
- privateWithin, coord = start.index)
456
- else {
457
- val sym = symAtAddr.get(start) match {
458
- case Some (preExisting) =>
459
- // assert(stubs contains preExisting, preExisting)
460
- // stubs -= preExisting
461
- preExisting
462
- case none =>
463
- ctx.newNakedSymbol(start.index)
464
- }
465
- val denot = ctx.SymDenotation (symbol = sym, owner = ctx.owner, name, flags, completer, privateWithin)
466
- sym.denot = denot
467
- sym
468
- }
469
- } // TODO set position
473
+ ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord = start.index)
474
+ else
475
+ ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord = start.index)
476
+ } // TODO set position somehow (but take care not to upset Symbol#isDefinedInCurrentRun)
470
477
sym.annotations = annots
471
478
ctx.enter(sym)
472
479
registerSym(start, sym)
473
480
if (isClass) {
474
481
sym.completer.withDecls(newScope)
475
482
forkAt(templateStart).indexTemplateParams()(localContext(sym))
476
483
}
484
+ goto(start)
477
485
sym
478
486
}
479
487
@@ -551,7 +559,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
551
559
while (currentAddr.index < end.index) {
552
560
nextByte match {
553
561
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
554
- val sym = createSymbol()
562
+ val sym = symbolAtCurrent()
563
+ skipTree()
555
564
if (sym.isTerm && ! sym.is(MethodOrLazyOrDeferred ))
556
565
initsFlags = EmptyFlags
557
566
else if (sym.isClass ||
@@ -586,7 +595,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
586
595
* `tag` starting at current address.
587
596
*/
588
597
def indexParams (tag : Int )(implicit ctx : Context ) =
589
- while (nextByte == tag) createSymbol()
598
+ while (nextByte == tag) {
599
+ symbolAtCurrent()
600
+ skipTree()
601
+ }
590
602
591
603
/** Create symbols for all type and value parameters of template starting
592
604
* at current address.
@@ -613,7 +625,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
613
625
val end = readEnd()
614
626
615
627
def readParams [T <: MemberDef ](tag : Int )(implicit ctx : Context ): List [T ] = {
616
- fork.indexParams(tag)
628
+ fork.indexParams(tag)(localContext(sym))
617
629
readIndexedParams(tag)
618
630
}
619
631
@@ -704,8 +716,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
704
716
TermRef .withSig(cls.owner.thisType, cls.name.sourceModuleName, Signature .NotAMethod )
705
717
else NoType
706
718
setClsInfo(Nil , assumedSelfType)
707
- val localDummy = ctx.newLocalDummy(cls)
708
- registerSym(start, localDummy)
719
+ val localDummy = symbolAtCurrent()
709
720
assert(readByte() == TEMPLATE )
710
721
val end = readEnd()
711
722
val tparams = readIndexedParams[TypeDef ](TYPEPARAM )
@@ -758,7 +769,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
758
769
}
759
770
760
771
def readTopLevel ()(implicit ctx : Context ): List [Tree ] = {
761
- ownerTree = new OwnerTree (NoAddr , fork, reader.endAddr)
762
772
@ tailrec def read (acc : ListBuffer [Tree ]): List [Tree ] = nextByte match {
763
773
case IMPORT | PACKAGE =>
764
774
acc += readIndexedStat(NoSymbol )
@@ -1010,32 +1020,62 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
1010
1020
}
1011
1021
}
1012
1022
1013
- class OwnerTree (val addr : Addr , reader : TreeReader , val end : Addr ) {
1023
+ /** A lazy datastructure that records how definitions are nested in TASTY data.
1024
+ * The structure is lazy because it needs to be computed only for forward references
1025
+ * to symbols that happen before the referenced symbol is created (see `symbolAt`).
1026
+ * Such forward references are rare.
1027
+ *
1028
+ * @param addr The address of tree representing an owning definition, NoAddr for root tree
1029
+ * @param tag The tag at `addr`. Used to determine which subtrees to scan for children
1030
+ * (i.e. if `tag` is template, don't scan member defs, as these belong already
1031
+ * to enclosing class).
1032
+ * @param reader The reader to be used for scanning for children
1033
+ * @param end The end of the owning definition
1034
+ */
1035
+ class OwnerTree (val addr : Addr , tag : Int , reader : TreeReader , val end : Addr ) {
1036
+
1037
+ /** All definitions that have the definition at `addr` as closest enclosing definition */
1014
1038
lazy val children : List [OwnerTree ] = {
1015
1039
val buf = new ListBuffer [OwnerTree ]
1016
- reader.scanTrees(buf, end)
1040
+ reader.scanTrees(buf, end, if (tag == TEMPLATE ) NoMemberDefs else AllDefs )
1017
1041
buf.toList
1018
1042
}
1043
+
1044
+ /** Find the owner of definition at `addr` */
1019
1045
def findOwner (addr : Addr )(implicit ctx : Context ): Symbol = {
1020
- // println(s"find owner $addr")
1021
- def search ( cs : List [ OwnerTree ], current : Symbol ) : Symbol = cs match {
1046
+ def search ( cs : List [ OwnerTree ], current : Symbol ) : Symbol =
1047
+ try cs match {
1022
1048
case ot :: cs1 =>
1023
- if (ot.addr.index == addr.index) {
1024
- // println(i"search ok $addr, owner = $current")
1049
+ if (ot.addr.index == addr.index)
1025
1050
current
1026
- }
1027
- else if (ot.addr.index < addr.index && addr.index < ot.end.index) {
1028
- val encl = reader.symbolAt(ot.addr)
1029
- // println(s"search $addr in ${ot.children} with $encl")
1030
- search(ot.children, encl)
1031
- }
1051
+ else if (ot.addr.index < addr.index && addr.index < ot.end.index)
1052
+ search(ot.children, reader.symbolAt(ot.addr))
1032
1053
else
1033
1054
search(cs1, current)
1034
1055
case Nil =>
1035
- throw new Error (" unattached tree" )
1056
+ throw new TreeWithoutOwner
1057
+ }
1058
+ catch {
1059
+ case ex : TreeWithoutOwner =>
1060
+ println(i " no owner for $addr among $cs" ) // DEBUG
1061
+ throw ex
1036
1062
}
1037
1063
search(children, NoSymbol )
1038
1064
}
1065
+
1039
1066
override def toString = s " OwnerTree( ${addr.index}, ${end.index}"
1040
1067
}
1041
1068
}
1069
+
1070
+ object TreeUnpickler {
1071
+
1072
+ /** An enumeration indicating which subtrees should be added to an OwnerTree. */
1073
+ type MemberDefMode = Int
1074
+ final val MemberDefsOnly = 0 // add only member defs; skip other statements
1075
+ final val NoMemberDefs = 1 // add only statements that are not member defs
1076
+ final val AllDefs = 2 // add everything
1077
+
1078
+ class TreeWithoutOwner extends Exception
1079
+ }
1080
+
1081
+
0 commit comments