diff --git a/compiler/src/dotty/tools/dotc/transform/Splicing.scala b/compiler/src/dotty/tools/dotc/transform/Splicing.scala index ad3f0322130d..393fe46b8438 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicing.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicing.scala @@ -242,9 +242,16 @@ class Splicing extends MacroTransform: else args.mapConserve(arg => transformLevel0QuoteContent(arg)(using quoteContext)) } cpy.Apply(tree)(cpy.Select(sel)(cpy.Apply(app)(fn, newArgs), nme.apply), quotesArgs) - case Apply(TypeApply(_, List(tpt)), List(quotes)) + case Apply(TypeApply(typeof, List(tpt)), List(quotes)) if tree.symbol == defn.QuotedTypeModule_of && containsCapturedType(tpt.tpe) => - ref(capturedType(tpt))(using ctx.withSource(tree.source)).withSpan(tree.span) + val newContent = capturedPartTypes(tpt) + newContent match + case block: Block => + inContext(ctx.withSource(tree.source)) { + Apply(TypeApply(typeof, List(newContent)), List(quotes)).withSpan(tree.span) + } + case _ => + ref(capturedType(newContent))(using ctx.withSource(tree.source)).withSpan(tree.span) case CapturedApplication(fn, argss) => transformCapturedApplication(tree, fn, argss) case _ => @@ -335,17 +342,46 @@ class Splicing extends MacroTransform: val bindingSym = refBindingMap.getOrElseUpdate(tree.symbol, (tree, newBinding))._2 ref(bindingSym) - private def capturedType(tree: Tree)(using Context): Symbol = - val tpe = tree.tpe.widenTermRefExpr - def newBinding = newSymbol( + private def newQuotedTypeClassBinding(tpe: Type)(using Context) = + newSymbol( spliceOwner, UniqueName.fresh(nme.Type).toTermName, Param, defn.QuotedTypeClass.typeRef.appliedTo(tpe), ) - val bindingSym = refBindingMap.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newBinding))._2 + + private def capturedType(tree: Tree)(using Context): Symbol = + val tpe = tree.tpe.widenTermRefExpr + val bindingSym = refBindingMap + .getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tpe)))._2 bindingSym + private def capturedPartTypes(tpt: Tree)(using Context): Tree = + val old = healedTypes + healedTypes = PCPCheckAndHeal.QuoteTypeTags(tpt.span) + val capturePartTypes = new TypeMap { + def apply(tp: Type) = tp match { + case typeRef @ TypeRef(prefix, _) if isCaptured(prefix.typeSymbol) || isCaptured(prefix.termSymbol) => + val termRef = refBindingMap + .getOrElseUpdate(typeRef.symbol, (TypeTree(typeRef), newQuotedTypeClassBinding(typeRef)))._2.termRef + val tagRef = healedTypes.nn.getTagRef(termRef) + tagRef + case _ => + mapOver(tp) + } + } + val captured = capturePartTypes(tpt.tpe.widenTermRefExpr) + val newHealedTypes = healedTypes.nn.getTypeTags + healedTypes = old + tpt match + case block: Block => + cpy.Block(block)(newHealedTypes ::: block.stats, TypeTree(captured)) + case _ => + if newHealedTypes.nonEmpty then + cpy.Block(tpt)(newHealedTypes, TypeTree(captured)) + else + tpt + private def getTagRefFor(tree: Tree)(using Context): Tree = val capturedTypeSym = capturedType(tree) TypeTree(healedTypes.nn.getTagRef(capturedTypeSym.termRef)) diff --git a/tests/pos-macros/i16615.scala b/tests/pos-macros/i16615.scala new file mode 100644 index 000000000000..3cc2d271fa87 --- /dev/null +++ b/tests/pos-macros/i16615.scala @@ -0,0 +1,19 @@ +import scala.quoted.* + +trait Api: + type Reader[E] + +def bugImpl[T: Type, Q[_]: Type](using Quotes) = + '{ + val p: Api = ??? + ${ + Type.of[p.Reader[T]] + Type.of[Q[p.Reader[T]]] + Type.of[p.Reader[Q[p.Reader[T]]]] + Type.of[List[p.Reader[T]]] + Type.of[p.Reader[List[p.Reader[T]]]] + Type.of[p.Reader[List[T]]] + Type.of[p.Reader[Q[T]]] + Expr(1) + } + }