Skip to content

Commit 0ab89e6

Browse files
Fix #16615 - crashes of path dependent types in spliced Type.of (#16773)
Fixes #16615 Previously it was assumed that the type in Type.of could be captured as a whole, which meant that path dependent types for which a separate @SplicedType hole definitions were included in a block, would end up with missing references. Now when find a block in Type.of, we try to analise all parts of the type separately, adding additional hole definitions to the block as necessary. For types that can be captured as a whole (those which did not have a block generated previously, meaning they do not include any @SplicedType hole definitions), old method is used. In essence, ended up replicating the trees proposed in the original issue thread, which were incredibly helpful.
2 parents 1fce02e + 90cdb69 commit 0ab89e6

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

compiler/src/dotty/tools/dotc/transform/Splicing.scala

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,16 @@ class Splicing extends MacroTransform:
242242
else args.mapConserve(arg => transformLevel0QuoteContent(arg)(using quoteContext))
243243
}
244244
cpy.Apply(tree)(cpy.Select(sel)(cpy.Apply(app)(fn, newArgs), nme.apply), quotesArgs)
245-
case Apply(TypeApply(_, List(tpt)), List(quotes))
245+
case Apply(TypeApply(typeof, List(tpt)), List(quotes))
246246
if tree.symbol == defn.QuotedTypeModule_of && containsCapturedType(tpt.tpe) =>
247-
ref(capturedType(tpt))(using ctx.withSource(tree.source)).withSpan(tree.span)
247+
val newContent = capturedPartTypes(tpt)
248+
newContent match
249+
case block: Block =>
250+
inContext(ctx.withSource(tree.source)) {
251+
Apply(TypeApply(typeof, List(newContent)), List(quotes)).withSpan(tree.span)
252+
}
253+
case _ =>
254+
ref(capturedType(newContent))(using ctx.withSource(tree.source)).withSpan(tree.span)
248255
case CapturedApplication(fn, argss) =>
249256
transformCapturedApplication(tree, fn, argss)
250257
case _ =>
@@ -335,17 +342,46 @@ class Splicing extends MacroTransform:
335342
val bindingSym = refBindingMap.getOrElseUpdate(tree.symbol, (tree, newBinding))._2
336343
ref(bindingSym)
337344

338-
private def capturedType(tree: Tree)(using Context): Symbol =
339-
val tpe = tree.tpe.widenTermRefExpr
340-
def newBinding = newSymbol(
345+
private def newQuotedTypeClassBinding(tpe: Type)(using Context) =
346+
newSymbol(
341347
spliceOwner,
342348
UniqueName.fresh(nme.Type).toTermName,
343349
Param,
344350
defn.QuotedTypeClass.typeRef.appliedTo(tpe),
345351
)
346-
val bindingSym = refBindingMap.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newBinding))._2
352+
353+
private def capturedType(tree: Tree)(using Context): Symbol =
354+
val tpe = tree.tpe.widenTermRefExpr
355+
val bindingSym = refBindingMap
356+
.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tpe)))._2
347357
bindingSym
348358

359+
private def capturedPartTypes(tpt: Tree)(using Context): Tree =
360+
val old = healedTypes
361+
healedTypes = PCPCheckAndHeal.QuoteTypeTags(tpt.span)
362+
val capturePartTypes = new TypeMap {
363+
def apply(tp: Type) = tp match {
364+
case typeRef @ TypeRef(prefix, _) if isCaptured(prefix.typeSymbol) || isCaptured(prefix.termSymbol) =>
365+
val termRef = refBindingMap
366+
.getOrElseUpdate(typeRef.symbol, (TypeTree(typeRef), newQuotedTypeClassBinding(typeRef)))._2.termRef
367+
val tagRef = healedTypes.nn.getTagRef(termRef)
368+
tagRef
369+
case _ =>
370+
mapOver(tp)
371+
}
372+
}
373+
val captured = capturePartTypes(tpt.tpe.widenTermRefExpr)
374+
val newHealedTypes = healedTypes.nn.getTypeTags
375+
healedTypes = old
376+
tpt match
377+
case block: Block =>
378+
cpy.Block(block)(newHealedTypes ::: block.stats, TypeTree(captured))
379+
case _ =>
380+
if newHealedTypes.nonEmpty then
381+
cpy.Block(tpt)(newHealedTypes, TypeTree(captured))
382+
else
383+
tpt
384+
349385
private def getTagRefFor(tree: Tree)(using Context): Tree =
350386
val capturedTypeSym = capturedType(tree)
351387
TypeTree(healedTypes.nn.getTagRef(capturedTypeSym.termRef))

tests/pos-macros/i16615.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import scala.quoted.*
2+
3+
trait Api:
4+
type Reader[E]
5+
6+
def bugImpl[T: Type, Q[_]: Type](using Quotes) =
7+
'{
8+
val p: Api = ???
9+
${
10+
Type.of[p.Reader[T]]
11+
Type.of[Q[p.Reader[T]]]
12+
Type.of[p.Reader[Q[p.Reader[T]]]]
13+
Type.of[List[p.Reader[T]]]
14+
Type.of[p.Reader[List[p.Reader[T]]]]
15+
Type.of[p.Reader[List[T]]]
16+
Type.of[p.Reader[Q[T]]]
17+
Expr(1)
18+
}
19+
}

0 commit comments

Comments
 (0)