Skip to content

Commit 511b02f

Browse files
committed
Fix quotes with references to path dependent types
1 parent f092f78 commit 511b02f

File tree

3 files changed

+88
-9
lines changed

3 files changed

+88
-9
lines changed

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,10 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
193193
tp match
194194
case tp: TypeRef =>
195195
healTypeRef(tp)
196-
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level > levelOf(tp.symbol) =>
197-
levelError(tp.symbol, tp, pos)
196+
case tp: TermRef =>
197+
val inconsistentRoot = levelInconsistentRootOfPath(tp)
198+
if inconsistentRoot.exists then levelError(inconsistentRoot, tp, pos)
199+
else tp
198200
case tp: AnnotatedType =>
199201
val newAnnotTree = transform(tp.annot.tree)
200202
derivedAnnotatedType(tp, apply(tp.parent), tp.annot.derivedAnnotation(newAnnotTree))
@@ -206,7 +208,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
206208
case prefix: TermRef if tp.symbol.isTypeSplice =>
207209
checkNotWildcardSplice(tp)
208210
if level == 0 then tp else getQuoteTypeTags.getTagRef(prefix)
209-
case prefix: TermRef if !prefix.symbol.isStatic && level > levelOf(prefix.symbol) =>
211+
case prefix: TermRef if levelInconsistentRootOfPath(prefix).exists =>
210212
dealiasAndTryHeal(prefix.symbol, tp, pos)
211213
case NoPrefix if level > levelOf(tp.symbol) && !tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot) =>
212214
dealiasAndTryHeal(tp.symbol, tp, pos)
@@ -220,6 +222,16 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
220222
if tp1 != tp then apply(tp1)
221223
else tryHeal(tp.symbol, tp, pos)
222224

225+
/** Return the root of this path if it is a variable defined in a previous level.
226+
* If the path is consistent, return NoSymbol.
227+
*/
228+
private def levelInconsistentRootOfPath(tp: Type)(using Context): Symbol =
229+
tp match
230+
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level > levelOf(tp.termSymbol) => tp.termSymbol
231+
case tp @ TermRef(prefix, _) if !tp.symbol.isStatic => levelInconsistentRootOfPath(prefix)
232+
case tp: ThisType if level > levelOf(tp.cls) => tp.cls
233+
case _ => NoSymbol
234+
223235
private def checkNotWildcardSplice(splice: TypeRef)(using Context): Unit =
224236
splice.prefix.termSymbol.info.argInfos match
225237
case (tb: TypeBounds) :: _ => report.error(em"Cannot splice $splice because it is a wildcard type", pos)

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ class Splicing extends MacroTransform:
222222
// Dealias references to captured types
223223
TypeTree(tree.tpe.dealias)
224224
else super.transform(tree)
225-
case tree: TypeTree =>
225+
case _: TypeTree | _: SingletonTypeTree =>
226226
if containsCapturedType(tree.tpe) && level >= 1 then getTagRefFor(tree)
227227
else tree
228228
case tree @ Assign(lhs: RefTree, rhs) =>
@@ -246,7 +246,7 @@ class Splicing extends MacroTransform:
246246
if tree.symbol == defn.QuotedTypeModule_of && containsCapturedType(tpt.tpe) =>
247247
val newContent = capturedPartTypes(tpt)
248248
newContent match
249-
case block: Block =>
249+
case block: Block =>
250250
inContext(ctx.withSource(tree.source)) {
251251
Apply(TypeApply(typeof, List(newContent)), List(quotes)).withSpan(tree.span)
252252
}
@@ -342,7 +342,7 @@ class Splicing extends MacroTransform:
342342
val bindingSym = refBindingMap.getOrElseUpdate(tree.symbol, (tree, newBinding))._2
343343
ref(bindingSym)
344344

345-
private def newQuotedTypeClassBinding(tpe: Type)(using Context) =
345+
private def newQuotedTypeClassBinding(tpe: Type)(using Context) =
346346
newSymbol(
347347
spliceOwner,
348348
UniqueName.fresh(nme.Type).toTermName,
@@ -353,15 +353,15 @@ class Splicing extends MacroTransform:
353353
private def capturedType(tree: Tree)(using Context): Symbol =
354354
val tpe = tree.tpe.widenTermRefExpr
355355
val bindingSym = refBindingMap
356-
.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tpe)))._2
356+
.getOrElseUpdate(tree.symbol, (TypeTree(tpe), newQuotedTypeClassBinding(tpe)))._2
357357
bindingSym
358358

359359
private def capturedPartTypes(tpt: Tree)(using Context): Tree =
360360
val old = healedTypes
361361
healedTypes = PCPCheckAndHeal.QuoteTypeTags(tpt.span)
362362
val capturePartTypes = new TypeMap {
363363
def apply(tp: Type) = tp match {
364-
case typeRef @ TypeRef(prefix, _) if isCaptured(prefix.typeSymbol) || isCaptured(prefix.termSymbol) =>
364+
case typeRef: TypeRef if containsCapturedType(typeRef) =>
365365
val termRef = refBindingMap
366366
.getOrElseUpdate(typeRef.symbol, (TypeTree(typeRef), newQuotedTypeClassBinding(typeRef)))._2.termRef
367367
val tagRef = healedTypes.nn.getTagRef(termRef)
@@ -376,7 +376,7 @@ class Splicing extends MacroTransform:
376376
tpt match
377377
case block: Block =>
378378
cpy.Block(block)(newHealedTypes ::: block.stats, TypeTree(captured))
379-
case _ =>
379+
case _ =>
380380
if newHealedTypes.nonEmpty then
381381
cpy.Block(tpt)(newHealedTypes, TypeTree(captured))
382382
else
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import scala.quoted.*
2+
3+
trait A:
4+
type T
5+
val b: B
6+
7+
trait B:
8+
type T
9+
10+
class Test:
11+
def testLocalPathsGlobalClasses(using Quotes): Unit =
12+
'{
13+
type T
14+
val a: A = ???
15+
${
16+
'{
17+
val _: T = ???
18+
val _: a.T = ???
19+
// val _: a.b.T = ??? // FIXME pickling
20+
val _: a.type = ???
21+
val _: a.b.type = ???
22+
}
23+
???
24+
}
25+
}
26+
27+
def testLocalPathsLocalClasses(using Quotes): Unit =
28+
'{
29+
type U
30+
trait C:
31+
type U
32+
val d: D
33+
trait D:
34+
type U
35+
val c: C = ???
36+
${
37+
'{
38+
val _: U = ???
39+
val _: c.U = ???
40+
val _: c.d.U = ???
41+
val _: c.type = ???
42+
val _: c.d.type = ???
43+
}
44+
???
45+
}
46+
}
47+
48+
def testThisPaths(using Quotes): Unit =
49+
'{
50+
trait E:
51+
type V
52+
val f: F
53+
${
54+
'{
55+
// val _: this.type = ??? // FIXME pickling E
56+
// val _: V = ??? // FIXME pickling E
57+
// val _: this.V = ??? // FIXME pickling E
58+
val _: this.f.V = ???
59+
// val _: this.type = ??? // FIXME pickling E
60+
val _: this.f.type = ???
61+
}
62+
???
63+
}
64+
trait F:
65+
type V
66+
???
67+
}

0 commit comments

Comments
 (0)