diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f07f1204ed18..01352b98a4cf 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -631,8 +631,16 @@ class TreeUnpickler(reader: TastyReader, * or else read definition. */ def readIndexedDef()(implicit ctx: Context): Tree = treeAtAddr.remove(currentAddr) match { - case Some(tree) => skipTree(); tree - case none => readNewDef() + case Some(tree) => + assert(tree != PoisonTree, s"Cyclic reference while unpickling definition at address ${currentAddr.index} in unit ${ctx.compilationUnit}") + skipTree() + tree + case none => + val start = currentAddr + treeAtAddr(start) = PoisonTree + val tree = readNewDef() + treeAtAddr.remove(start) + tree } private def readNewDef()(implicit ctx: Context): Tree = { @@ -1169,6 +1177,9 @@ class TreeUnpickler(reader: TastyReader, object TreeUnpickler { + /** A marker value used to detect cyclic reference while unpickling definitions. */ + @sharable val PoisonTree: tpd.Tree = Thicket(Nil) + /** An enumeration indicating which subtrees should be added to an OwnerTree. */ type MemberDefMode = Int final val MemberDefsOnly = 0 // add only member defs; skip other statements