diff --git a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala index 15a1a823589c..8b58f18bca52 100644 --- a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala @@ -17,13 +17,13 @@ import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.config.ScalaRelease.* -import scala.collection.mutable import dotty.tools.dotc.core.Annotations._ import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.quoted._ import dotty.tools.dotc.inlines.Inlines import scala.annotation.constructorOnly +import scala.collection.mutable /** Translates quoted terms and types to `unpickleExprV2` or `unpickleType` method calls. * @@ -106,16 +106,19 @@ class PickleQuotes extends MacroTransform { private def extractHolesContents(quote: tpd.Quote)(using Context): (List[Tree], tpd.Quote) = class HoleContentExtractor extends Transformer: private val holeContents = List.newBuilder[Tree] + private val stagedClasses = mutable.HashSet.empty[Symbol] override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match case tree @ Hole(isTerm, _, _, content) => assert(isTerm) assert(!content.isEmpty) holeContents += content - val holeType = getTermHoleType(tree.tpe) + val holeType = getPicklableHoleType(tree.tpe, stagedClasses) val hole = untpd.cpy.Hole(tree)(content = EmptyTree).withType(holeType) cpy.Inlined(tree)(EmptyTree, Nil, hole) case tree: DefTree => + if tree.symbol.isClass then + stagedClasses += tree.symbol val newAnnotations = tree.symbol.annotations.mapconserve { annot => annot.derivedAnnotation(transform(annot.tree)(using ctx.withOwner(tree.symbol))) } @@ -134,19 +137,6 @@ class PickleQuotes extends MacroTransform { } } - /** Remove references to local types that will not be defined in this quote */ - private def getTermHoleType(using Context) = new TypeMap() { - override def apply(tp: Type): Type = tp match - case tp @ TypeRef(NoPrefix, _) => - // reference to term with a type defined in outer quote - getTypeHoleType(tp) - case tp @ TermRef(NoPrefix, _) => - // widen term refs to terms defined in outer quote - apply(tp.widenTermRefExpr) - case tp => - mapOver(tp) - } - /** Get the holeContents of the transformed tree */ def getContents() = val res = holeContents.result @@ -196,11 +186,11 @@ class PickleQuotes extends MacroTransform { cpy.Quote(quote)(Block(tdefs, body1), quote.tags) private def mkTagSymbolAndAssignType(typeArg: Tree, idx: Int)(using Context): TypeDef = { - val holeType = getTypeHoleType(typeArg.tpe.select(tpnme.Underlying)) + val holeType = getPicklableHoleType(typeArg.tpe.select(tpnme.Underlying), _ => false) val hole = untpd.cpy.Hole(typeArg)(isTerm = false, idx, Nil, EmptyTree).withType(holeType) val local = newSymbol( owner = ctx.owner, - name = UniqueName.fresh(hole.tpe.dealias.typeSymbol.name.toTypeName), + name = UniqueName.fresh(typeArg.symbol.name.toTypeName), flags = Synthetic, info = TypeAlias(typeArg.tpe.select(tpnme.Underlying)), coord = typeArg.span @@ -209,25 +199,11 @@ class PickleQuotes extends MacroTransform { ctx.typeAssigner.assignType(untpd.TypeDef(local.name, hole), local).withSpan(typeArg.span) } - /** Remove references to local types that will not be defined in this quote */ - private def getTypeHoleType(using Context) = new TypeMap() { - override def apply(tp: Type): Type = tp match - case tp: TypeRef if tp.typeSymbol.isTypeSplice => - apply(tp.dealias) - case tp @ TypeRef(pre, _) if isLocalPath(pre) => - val hiBound = tp.typeSymbol.info match - case info: ClassInfo => info.parents.reduce(_ & _) - case info => info.hiBound - apply(hiBound) - case tp => - mapOver(tp) - - private def isLocalPath(tp: Type): Boolean = tp match - case NoPrefix => true - case tp: TermRef if !tp.symbol.is(Package) => isLocalPath(tp.prefix) - case tp => false - } - + /** Avoid all non-static types except those defined in the quote. */ + private def getPicklableHoleType(tpe: Type, isStagedClasses: Symbol => Boolean)(using Context) = + new TypeOps.AvoidMap { + def toAvoid(tp: NamedType) = !isStagedClasses(tp.typeSymbol) && !isStaticPrefix(tp) + }.apply(tpe) } object PickleQuotes {