diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index d70b56fca43d..def27742c189 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -405,7 +405,14 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { pickleType(tp) } case This(qual) => - if (qual.isEmpty) pickleType(tree.tpe) + if (qual.isEmpty) + if tree.tpe.isSingleton then pickleType(tree.tpe) + else + // This may happen when pickling a `This` inside a capture set. See #19662. + // In this case, we pickle the tree as null.asInstanceOf[tree.tpe]. + // Since the pickled tree is not the same as the input, special handling is needed + // in the tree printer when testing the pickler. See [[PlainPrinter#homogenize]]. + pickleTree(Literal(Constant(null)).cast(tree.tpe).withSpan(tree.span)) else { writeByte(QUALTHIS) val ThisType(tref) = tree.tpe: @unchecked diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 8fc0c568e125..e189e94829d0 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -15,7 +15,7 @@ import util.SourcePosition import scala.util.control.NonFatal import scala.annotation.switch import config.{Config, Feature} -import cc.{CapturingType, RetainingType, CaptureSet, ReachCapability, MaybeCapability, isBoxed, levelOwner, retainedElems} +import cc.{CapturingType, RetainingType, CaptureSet, ReachCapability, MaybeCapability, isBoxed, levelOwner, retainedElems, isRetainsLike} class PlainPrinter(_ctx: Context) extends Printer { @@ -60,7 +60,8 @@ class PlainPrinter(_ctx: Context) extends Printer { case OrType(tp1, tp2) => homogenize(tp1) | homogenize(tp2) case AnnotatedType(parent, annot) - if !ctx.mode.is(Mode.Type) && annot.symbol == defn.UncheckedVarianceAnnot => + if !ctx.mode.is(Mode.Type) && annot.symbol == defn.UncheckedVarianceAnnot + || annot.symbol.isRetainsLike => homogenize(parent) case tp: SkolemType => homogenize(tp.info) diff --git a/tests/pos-custom-args/captures/i19662.scala b/tests/pos-custom-args/captures/i19662.scala new file mode 100644 index 000000000000..24b6272a8f45 --- /dev/null +++ b/tests/pos-custom-args/captures/i19662.scala @@ -0,0 +1,9 @@ +// Modified from #19662 to make it independent of the cc stdlib. +import language.experimental.captureChecking +trait MySeq[+A] { self: MySeq[A]^ => + def map[B](f: A => B): MySeq[B]^{this, f} +} +object MySeq: + def apply(x: Int): MySeq[Int] = ??? +class C: + private def foo = MySeq(5).map { i => i }