@@ -959,6 +959,51 @@ class TreeUnpickler(reader: TastyReader,
959959 tree.setDefTree
960960 }
961961
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+
9621007 private def readTemplate (using Context ): Template = {
9631008 val start = currentAddr
9641009 assert(sourcePathAt(start).isEmpty)
@@ -981,12 +1026,8 @@ class TreeUnpickler(reader: TastyReader,
9811026 while (bodyIndexer.reader.nextByte != DEFDEF ) bodyIndexer.skipTree()
9821027 bodyIndexer.indexStats(end)
9831028 }
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)
9901031 val parentTypes = parents.map(_.tpe.dealias)
9911032 val self =
9921033 if (nextByte == SELFDEF ) {
@@ -1000,7 +1041,13 @@ class TreeUnpickler(reader: TastyReader,
10001041 selfInfo = if (self.isEmpty) NoType else self.tpt.tpe)
10011042 .integrateOpaqueMembers
10021043 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
10041051
10051052 val lazyStats = readLater(end, rdr => {
10061053 val stats = rdr.readIndexedStats(localDummy, end)
@@ -1009,7 +1056,7 @@ class TreeUnpickler(reader: TastyReader,
10091056 defn.patchStdLibClass(cls)
10101057 NamerOps .addConstructorProxies(cls)
10111058 setSpan(start,
1012- untpd.Template (constr, mappedParents, Nil , self, lazyStats)
1059+ untpd.Template (constr, mappedParents, self, lazyStats)
10131060 .withType(localDummy.termRef))
10141061 }
10151062
0 commit comments