@@ -21,6 +21,7 @@ import dotty.tools.dotc.transform.TreeMapWithStages._
2121import dotty .tools .dotc .typer .Checking
2222import dotty .tools .dotc .typer .Implicits .SearchFailureType
2323import dotty .tools .dotc .typer .Inliner
24+ import dotty .tools .dotc .core .Annotations ._
2425
2526import scala .collection .mutable
2627import dotty .tools .dotc .util .SourcePosition
@@ -54,10 +55,26 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
5455
5556 /** Transform quoted trees while maintaining phase correctness */
5657 override protected def transformQuotation (body : Tree , quote : Tree )(implicit ctx : Context ): Tree = {
58+ val taggedTypes = new PCPCheckAndHeal .QuoteTypeTags (quote.span)(using ctx)
59+ given Context =
60+ if level(ctx) == 0 then contextWithQuoteTypeTags(taggedTypes)(ctx)
61+ else ctx
62+
5763 if (ctx.property(InAnnotation ).isDefined)
5864 ctx.error(" Cannot have a quote in an annotation" , quote.sourcePos)
59- val body1 = transform(body)(quoteContext)
60- super .transformQuotation(body1, quote)
65+
66+ val body1 =
67+ transform(body)(quoteContext)
68+
69+ val body2 =
70+ if level != 0 then body1
71+ else
72+ val tags = taggedTypes.getTypeTags
73+ if tags.isEmpty then body1
74+ else tpd.Block (taggedTypes.getTypeTags, body1).withSpan(body.span)
75+
76+ super .transformQuotation(body2, quote)
77+
6178 }
6279
6380 /** Transform splice
@@ -73,7 +90,9 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
7390 // internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
7491 val tp = checkType(splice.sourcePos).apply(splice.tpe.widenTermRefExpr)
7592 cpy.Apply (splice)(cpy.TypeApply (fun)(fun.fun, tpd.TypeTree (tp) :: Nil ), body1 :: Nil )
76- case splice : Select => cpy.Select (splice)(body1, splice.name)
93+ case splice : Select =>
94+ val tagRef = getQuoteTypeTags.getTagRef(splice.qualifier.tpe.asInstanceOf [TermRef ])
95+ ref(tagRef).withSpan(splice.span)
7796 }
7897 }
7998
@@ -120,11 +139,14 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
120139 case tp : TypeRef if tp.symbol.isSplice =>
121140 if (tp.isTerm)
122141 ctx.error(i " splice outside quotes " , pos)
123- tp
142+ if level > 0 then getQuoteTypeTags.getTagRef(tp.prefix.asInstanceOf [TermRef ])
143+ else tp
124144 case tp : TypeRef if tp.symbol == defn.QuotedTypeClass .typeParams.head =>
125- // Adapt direct references to the type of the type parameter T of a quoted.Type[T].
126- // Replace it with a properly encoded type splice. This is the normal for expected for type splices.
127- tp.prefix.select(tpnme.splice)
145+ if level > 0 then
146+ // Adapt direct references to the type of the type parameter T of a quoted.Type[T].
147+ // Replace it with a properly encoded type splice. This is the normal for expected for type splices.
148+ getQuoteTypeTags.getTagRef(tp.prefix.asInstanceOf [TermRef ])
149+ else tp
128150 case tp : NamedType =>
129151 checkSymLevel(tp.symbol, tp, pos) match {
130152 case Some (tpRef) => tpRef.tpe
@@ -201,6 +223,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
201223 sym.isClass // reference to this in inline methods
202224 )
203225 case None =>
226+ (sym.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot ) && level > 0 ) ||
204227 sym.is(Package ) || sym.owner.isStaticOwner || levelOK(sym.owner)
205228 }
206229
@@ -212,10 +235,11 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
212235 protected def tryHeal (sym : Symbol , tp : TypeRef , pos : SourcePosition )(implicit ctx : Context ): Option [Tree ] = {
213236 val reqType = defn.QuotedTypeClass .typeRef.appliedTo(tp)
214237 val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
238+
215239 tag.tpe match
216240 case tp : TermRef =>
217241 checkStable(tp, pos)
218- Some (tag.select(tpnme.splice ))
242+ Some (ref(getQuoteTypeTags.getTagRef(tp) ))
219243 case _ : SearchFailureType =>
220244 levelError(sym, tp, pos,
221245 i """
@@ -242,3 +266,34 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
242266 }
243267}
244268
269+ object PCPCheckAndHeal {
270+ import tpd ._
271+
272+ class QuoteTypeTags (span : Span )(using ctx : Context ) {
273+
274+ private val tags = collection.mutable.LinkedHashMap .empty[Symbol , TypeDef ]
275+
276+ def getTagRef (spliced : TermRef ): TypeRef = {
277+ val typeDef = tags.getOrElseUpdate(spliced.symbol, mkTagSymbolAndAssignType(spliced))
278+ typeDef.symbol.typeRef
279+ }
280+
281+ def getTypeTags : List [TypeDef ] = tags.valuesIterator.toList
282+
283+ private def mkTagSymbolAndAssignType (spliced : TermRef ): TypeDef = {
284+ val splicedTree = tpd.ref(spliced).withSpan(span)
285+ val rhs = splicedTree.select(tpnme.splice).withSpan(span)
286+ val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree (rhs, rhs), rhs, rhs, EmptyTree )
287+ val local = ctx.newSymbol(
288+ owner = ctx.owner,
289+ name = UniqueName .fresh((splicedTree.symbol.name.toString + " $_" ).toTermName).toTypeName,
290+ flags = Synthetic ,
291+ info = TypeAlias (splicedTree.tpe.select(tpnme.splice)),
292+ coord = span).asType
293+ local.addAnnotation(Annotation (defn.InternalQuoted_QuoteTypeTagAnnot ))
294+ ctx.typeAssigner.assignType(untpd.TypeDef (local.name, alias), local)
295+ }
296+
297+ }
298+
299+ }
0 commit comments