Skip to content

Commit c720e5a

Browse files
Place staged type captures in Quote AST (#17424)
This change makes it easier to handle instances `Type[T]` that are inserted into a level 0 quote. These used to be encoded in the staging phase as type aliases `@TypeSplice type A = t.Underlying`. This makes it hard to debug and check invariants. Instead, we can collect the list of type tags needed and store them in the quote. At the same time, we can convert references to those types into `t.Underlying`. We can generate the `@TypeSplice type A = t.Underlying` just before pickling and replace all references to `t.Underlying` with `A` at that point. This is only an internal representation change while transforming the quote. It will not affect TASTy.
2 parents e8c6ebe + 0ee80f9 commit c720e5a

25 files changed

+249
-251
lines changed

compiler/src/dotty/tools/dotc/CompilationUnit.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ object CompilationUnit {
157157
if tree.symbol.is(Flags.Inline) then
158158
containsInline = true
159159
tree match
160-
case tpd.Quote(_) =>
160+
case _: tpd.Quote =>
161161
containsQuote = true
162162
case tree: tpd.Apply if tree.symbol == defn.QuotedTypeModule_of =>
163163
containsQuote = true

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1976,7 +1976,7 @@ object desugar {
19761976
trees foreach collect
19771977
case Block(Nil, expr) =>
19781978
collect(expr)
1979-
case Quote(body) =>
1979+
case Quote(body, _) =>
19801980
new UntypedTreeTraverser {
19811981
def traverse(tree: untpd.Tree)(using Context): Unit = tree match {
19821982
case Splice(expr) => collect(expr)

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -690,9 +690,14 @@ object Trees {
690690
* when type checking. TASTy files will not contain type quotes. Type quotes are used again
691691
* in the `staging` phase to represent the reification of `Type.of[T]]`.
692692
*
693+
* Type tags `tags` are always empty before the `staging` phase. Tags for stage inconsistent
694+
* types are added in the `staging` phase to level 0 quotes. Tags for types that refer to
695+
* definitions in an outer quote are added in the `splicing` phase
696+
*
693697
* @param body The tree that was quoted
698+
* @param tags Term references to instances of `Type[T]` for `T`s that are used in the quote
694699
*/
695-
case class Quote[+T <: Untyped] private[ast] (body: Tree[T])(implicit @constructorOnly src: SourceFile)
700+
case class Quote[+T <: Untyped] private[ast] (body: Tree[T], tags: List[Tree[T]])(implicit @constructorOnly src: SourceFile)
696701
extends TermTree[T] {
697702
type ThisTree[+T <: Untyped] = Quote[T]
698703

@@ -1313,9 +1318,9 @@ object Trees {
13131318
case tree: Inlined if (call eq tree.call) && (bindings eq tree.bindings) && (expansion eq tree.expansion) => tree
13141319
case _ => finalize(tree, untpd.Inlined(call, bindings, expansion)(sourceFile(tree)))
13151320
}
1316-
def Quote(tree: Tree)(body: Tree)(using Context): Quote = tree match {
1317-
case tree: Quote if (body eq tree.body) => tree
1318-
case _ => finalize(tree, untpd.Quote(body)(sourceFile(tree)))
1321+
def Quote(tree: Tree)(body: Tree, tags: List[Tree])(using Context): Quote = tree match {
1322+
case tree: Quote if (body eq tree.body) && (tags eq tree.tags) => tree
1323+
case _ => finalize(tree, untpd.Quote(body, tags)(sourceFile(tree)))
13191324
}
13201325
def Splice(tree: Tree)(expr: Tree)(using Context): Splice = tree match {
13211326
case tree: Splice if (expr eq tree.expr) => tree
@@ -1558,8 +1563,8 @@ object Trees {
15581563
case Thicket(trees) =>
15591564
val trees1 = transform(trees)
15601565
if (trees1 eq trees) tree else Thicket(trees1)
1561-
case tree @ Quote(body) =>
1562-
cpy.Quote(tree)(transform(body)(using quoteContext))
1566+
case Quote(body, tags) =>
1567+
cpy.Quote(tree)(transform(body)(using quoteContext), transform(tags))
15631568
case tree @ Splice(expr) =>
15641569
cpy.Splice(tree)(transform(expr)(using spliceContext))
15651570
case tree @ Hole(isTerm, idx, args, content, tpt) =>
@@ -1703,8 +1708,8 @@ object Trees {
17031708
this(this(x, arg), annot)
17041709
case Thicket(ts) =>
17051710
this(x, ts)
1706-
case Quote(body) =>
1707-
this(x, body)(using quoteContext)
1711+
case Quote(body, tags) =>
1712+
this(this(x, body)(using quoteContext), tags)
17081713
case Splice(expr) =>
17091714
this(x, expr)(using spliceContext)
17101715
case Hole(_, _, args, content, tpt) =>

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
170170
def Inlined(call: Tree, bindings: List[MemberDef], expansion: Tree)(using Context): Inlined =
171171
ta.assignType(untpd.Inlined(call, bindings, expansion), bindings, expansion)
172172

173-
def Quote(body: Tree)(using Context): Quote =
174-
untpd.Quote(body).withBodyType(body.tpe)
173+
def Quote(body: Tree, tags: List[Tree])(using Context): Quote =
174+
untpd.Quote(body, tags).withBodyType(body.tpe)
175175

176176
def Splice(expr: Tree, tpe: Type)(using Context): Splice =
177177
untpd.Splice(expr).withType(tpe)

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
397397
def SeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit src: SourceFile): SeqLiteral = new SeqLiteral(elems, elemtpt)
398398
def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit src: SourceFile): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt)
399399
def Inlined(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree)(implicit src: SourceFile): Inlined = new Inlined(call, bindings, expansion)
400-
def Quote(body: Tree)(implicit src: SourceFile): Quote = new Quote(body)
400+
def Quote(body: Tree, tags: List[Tree])(implicit src: SourceFile): Quote = new Quote(body, tags)
401401
def Splice(expr: Tree)(implicit src: SourceFile): Splice = new Splice(expr)
402402
def TypeTree()(implicit src: SourceFile): TypeTree = new TypeTree()
403403
def InferredTypeTree()(implicit src: SourceFile): TypeTree = new InferredTypeTree()

compiler/src/dotty/tools/dotc/core/Phases.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ object Phases {
211211
private var mySbtExtractDependenciesPhase: Phase = _
212212
private var myPicklerPhase: Phase = _
213213
private var myInliningPhase: Phase = _
214+
private var myStagingPhase: Phase = _
214215
private var mySplicingPhase: Phase = _
215216
private var myFirstTransformPhase: Phase = _
216217
private var myCollectNullableFieldsPhase: Phase = _
@@ -235,6 +236,7 @@ object Phases {
235236
final def sbtExtractDependenciesPhase: Phase = mySbtExtractDependenciesPhase
236237
final def picklerPhase: Phase = myPicklerPhase
237238
final def inliningPhase: Phase = myInliningPhase
239+
final def stagingPhase: Phase = myStagingPhase
238240
final def splicingPhase: Phase = mySplicingPhase
239241
final def firstTransformPhase: Phase = myFirstTransformPhase
240242
final def collectNullableFieldsPhase: Phase = myCollectNullableFieldsPhase
@@ -262,6 +264,7 @@ object Phases {
262264
mySbtExtractDependenciesPhase = phaseOfClass(classOf[sbt.ExtractDependencies])
263265
myPicklerPhase = phaseOfClass(classOf[Pickler])
264266
myInliningPhase = phaseOfClass(classOf[Inlining])
267+
myStagingPhase = phaseOfClass(classOf[Staging])
265268
mySplicingPhase = phaseOfClass(classOf[Splicing])
266269
myFirstTransformPhase = phaseOfClass(classOf[FirstTransform])
267270
myCollectNullableFieldsPhase = phaseOfClass(classOf[CollectNullableFields])
@@ -449,6 +452,7 @@ object Phases {
449452
def sbtExtractDependenciesPhase(using Context): Phase = ctx.base.sbtExtractDependenciesPhase
450453
def picklerPhase(using Context): Phase = ctx.base.picklerPhase
451454
def inliningPhase(using Context): Phase = ctx.base.inliningPhase
455+
def stagingPhase(using Context): Phase = ctx.base.stagingPhase
452456
def splicingPhase(using Context): Phase = ctx.base.splicingPhase
453457
def firstTransformPhase(using Context): Phase = ctx.base.firstTransformPhase
454458
def refchecksPhase(using Context): Phase = ctx.base.refchecksPhase

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ class TreePickler(pickler: TastyPickler) {
665665
pickleTree(hi)
666666
pickleTree(alias)
667667
}
668-
case tree @ Quote(body) =>
668+
case tree @ Quote(body, Nil) =>
669669
// TODO: Add QUOTE tag to TASTy
670670
assert(body.isTerm,
671671
"""Quote with type should not be pickled.

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1269,7 +1269,7 @@ class TreeUnpickler(reader: TastyReader,
12691269

12701270
def quotedExpr(fn: Tree, args: List[Tree]): Tree =
12711271
val TypeApply(_, targs) = fn: @unchecked
1272-
untpd.Quote(args.head).withBodyType(targs.head.tpe)
1272+
untpd.Quote(args.head, Nil).withBodyType(targs.head.tpe)
12731273

12741274
def splicedExpr(fn: Tree, args: List[Tree]): Tree =
12751275
val TypeApply(_, targs) = fn: @unchecked

compiler/src/dotty/tools/dotc/inlines/Inliner.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,7 @@ class Inliner(val call: tpd.Tree)(using Context):
827827

828828
override def typedQuote(tree: untpd.Quote, pt: Type)(using Context): Tree =
829829
super.typedQuote(tree, pt) match
830-
case Quote(Splice(inner)) => inner
830+
case Quote(Splice(inner), _) => inner
831831
case tree1 =>
832832
ctx.compilationUnit.needsStaging = true
833833
tree1

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,7 @@ object Parsers {
12431243
}
12441244
}
12451245
in.nextToken()
1246-
Quote(t)
1246+
Quote(t, Nil)
12471247
}
12481248
else
12491249
if !in.featureEnabled(Feature.symbolLiterals) then
@@ -2480,7 +2480,7 @@ object Parsers {
24802480
val body =
24812481
if (in.token == LBRACKET) inBrackets(typ())
24822482
else stagedBlock()
2483-
Quote(body)
2483+
Quote(body, Nil)
24842484
}
24852485
}
24862486
case NEW =>

0 commit comments

Comments
 (0)