@@ -959,6 +959,51 @@ class TreeUnpickler(reader: TastyReader,
959
959
tree.setDefTree
960
960
}
961
961
962
+ /** Read enough of parent to determine its type, without reading arguments
963
+ * of applications. This is necessary to make TreeUnpickler as lazy as Namer
964
+ * in this regard. See i16673 for a test case.
965
+ */
966
+ private def readParentType ()(using Context ): Type =
967
+ readByte() match
968
+ case TYPEAPPLY =>
969
+ val end = readEnd()
970
+ val tycon = readParentType()
971
+ if tycon.typeParams.isEmpty then
972
+ goto(end)
973
+ tycon
974
+ else
975
+ val args = until(end)(readTpt())
976
+ val cls = tycon.classSymbol
977
+ assert(cls.typeParams.hasSameLengthAs(args))
978
+ cls.typeRef.appliedTo(args.tpes)
979
+ case APPLY | BLOCK =>
980
+ val end = readEnd()
981
+ try readParentType()
982
+ finally goto(end)
983
+ case SELECTin =>
984
+ val end = readEnd()
985
+ readName()
986
+ readTerm() match
987
+ case nu : New =>
988
+ try nu.tpe
989
+ finally goto(end)
990
+ case SHAREDterm =>
991
+ forkAt(readAddr()).readParentType()
992
+
993
+ /** Read template parents
994
+ * @param withArgs if false, only read enough of parent trees to determine their type
995
+ * but skip constructor arguments. Return any trees that were partially
996
+ * parsed in this way as InferredTypeTrees.
997
+ */
998
+ def readParents (withArgs : Boolean )(using Context ): List [Tree ] =
999
+ collectWhile(nextByte != SELFDEF && nextByte != DEFDEF ) {
1000
+ nextUnsharedTag match
1001
+ case APPLY | TYPEAPPLY | BLOCK =>
1002
+ if withArgs then readTerm()
1003
+ else InferredTypeTree ().withType(readParentType())
1004
+ case _ => readTpt()
1005
+ }
1006
+
962
1007
private def readTemplate (using Context ): Template = {
963
1008
val start = currentAddr
964
1009
assert(sourcePathAt(start).isEmpty)
@@ -981,12 +1026,8 @@ class TreeUnpickler(reader: TastyReader,
981
1026
while (bodyIndexer.reader.nextByte != DEFDEF ) bodyIndexer.skipTree()
982
1027
bodyIndexer.indexStats(end)
983
1028
}
984
- val parents = collectWhile(nextByte != SELFDEF && nextByte != DEFDEF ) {
985
- nextUnsharedTag match {
986
- case APPLY | TYPEAPPLY | BLOCK => readTerm()(using parentCtx)
987
- case _ => readTpt()(using parentCtx)
988
- }
989
- }
1029
+ val parentReader = fork
1030
+ val parents = readParents(withArgs = false )(using parentCtx)
990
1031
val parentTypes = parents.map(_.tpe.dealias)
991
1032
val self =
992
1033
if (nextByte == SELFDEF ) {
@@ -1000,7 +1041,13 @@ class TreeUnpickler(reader: TastyReader,
1000
1041
selfInfo = if (self.isEmpty) NoType else self.tpt.tpe)
1001
1042
.integrateOpaqueMembers
1002
1043
val constr = readIndexedDef().asInstanceOf [DefDef ]
1003
- val mappedParents = parents.map(_.changeOwner(localDummy, constr.symbol))
1044
+ val mappedParents : LazyTreeList =
1045
+ if parents.exists(_.isInstanceOf [InferredTypeTree ]) then
1046
+ // parents were not read fully, will need to be read again later on demand
1047
+ new LazyReader (parentReader, localDummy, ctx.mode, ctx.source,
1048
+ _.readParents(withArgs = true )
1049
+ .map(_.changeOwner(localDummy, constr.symbol)))
1050
+ else parents
1004
1051
1005
1052
val lazyStats = readLater(end, rdr => {
1006
1053
val stats = rdr.readIndexedStats(localDummy, end)
@@ -1009,7 +1056,7 @@ class TreeUnpickler(reader: TastyReader,
1009
1056
defn.patchStdLibClass(cls)
1010
1057
NamerOps .addConstructorProxies(cls)
1011
1058
setSpan(start,
1012
- untpd.Template (constr, mappedParents, Nil , self, lazyStats)
1059
+ untpd.Template (constr, mappedParents, self, lazyStats)
1013
1060
.withType(localDummy.termRef))
1014
1061
}
1015
1062
0 commit comments