Skip to content

Commit 3c2ae12

Browse files
committed
Re-architecture quote pickling
Separate the logic that creates holes in quotes from the logic that pickles the quotes. Holes are created in the `Splicer` phase and the result of the transformation can be `-Ycheck`ed. Now, the `PickleQuotes` phase only needs to extract the contents of the holes, pickle the quote and put them into a call to `unpickleExprV2`/`unpickleTypeV2`. We add `unpickleExprV2` to support some optimization in the encoding of the pickled quote. Namely we removed an unnecessary lambda from the arguments of the hole passed into the contents of the hole. By not changing `unpickleExpr` the current compiler will be able to handle the old encoding in binaries compiled with older compilers. The `unpickleTypeV2` is just a version of `unpickleType` that does not take the `termHole` parameter which is always `null`. With `-Yscala-relese` 3.0 or 3.1, the compiler will generate calls to the old `unpickleExpr`/`unpickleType`. Fixes #8100 Fixes #12440 Fixes #13563 Fixes #14337 Fixes #14373 Closes #13732
1 parent 8922c88 commit 3c2ae12

File tree

81 files changed

+1414
-516
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1414
-516
lines changed

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

+1-7
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,10 @@ class CompilationUnit protected (val source: SourceFile) {
4646
var needsMirrorSupport: Boolean = false
4747

4848
/** Will be set to `true` if contains `Quote`.
49-
* The information is used in phase `Staging` in order to avoid traversing trees that need no transformations.
49+
* The information is used in phase `Staging`/`Splicing`/`PickleQuotes` in order to avoid traversing trees that need no transformations.
5050
*/
5151
var needsStaging: Boolean = false
5252

53-
/** Will be set to `true` if contains `Quote` that needs to be pickled
54-
* The information is used in phase `PickleQuotes` in order to avoid traversing trees that need no transformations.
55-
*/
56-
var needsQuotePickling: Boolean = false
57-
5853
var suspended: Boolean = false
5954
var suspendedAtInliningPhase: Boolean = false
6055

@@ -103,7 +98,6 @@ object CompilationUnit {
10398
val force = new Force
10499
force.traverse(unit1.tpdTree)
105100
unit1.needsStaging = force.containsQuote
106-
unit1.needsQuotePickling = force.containsQuote
107101
unit1.needsInlining = force.containsInline
108102
}
109103
unit1

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

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class Compiler {
5454
List(new Inlining) :: // Inline and execute macros
5555
List(new PostInlining) :: // Add mirror support for inlined code
5656
List(new Staging) :: // Check staging levels and heal staged types
57+
List(new Splicing) :: // Replace level 1 splices with holes
5758
List(new PickleQuotes) :: // Turn quoted trees into explicit run-time data structures
5859
Nil
5960

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,11 @@ class TreeTypeMap(
133133
val bind1 = tmap.transformSub(bind)
134134
val expr1 = tmap.transform(expr)
135135
cpy.Labeled(labeled)(bind1, expr1)
136-
case Hole(isTermHole, n, args) =>
137-
Hole(isTermHole, n, args.mapConserve(transform)).withSpan(tree.span).withType(mapType(tree.tpe))
136+
case tree @ Hole(_, _, args, content, tpt) =>
137+
val args1 = args.mapConserve(transform)
138+
val content1 = transform(content)
139+
val tpt1 = transform(tpt)
140+
cpy.Hole(tree)(args = args1, content = content1, tpt = tpt1)
138141
case lit @ Literal(Constant(tpe: Type)) =>
139142
cpy.Literal(lit)(Constant(mapType(tpe)))
140143
case tree1 =>

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

+25-7
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,11 @@ object Trees {
502502
def forwardTo: Tree[T] = fun
503503
}
504504

505+
object GenericApply:
506+
def unapply[T >: Untyped](tree: Tree[T]): Option[(Tree[T], List[Tree[T]])] = tree match
507+
case tree: GenericApply[T] => Some((tree.fun, tree.args))
508+
case _ => None
509+
505510
/** The kind of application */
506511
enum ApplyKind:
507512
case Regular // r.f(x)
@@ -524,8 +529,6 @@ object Trees {
524529
attachmentOrElse(untpd.KindOfApply, ApplyKind.Regular)
525530
}
526531

527-
528-
529532
/** fun[args] */
530533
case class TypeApply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]])(implicit @constructorOnly src: SourceFile)
531534
extends GenericApply[T] {
@@ -971,10 +974,16 @@ object Trees {
971974
def genericEmptyValDef[T >: Untyped]: ValDef[T] = theEmptyValDef.asInstanceOf[ValDef[T]]
972975
def genericEmptyTree[T >: Untyped]: Thicket[T] = theEmptyTree.asInstanceOf[Thicket[T]]
973976

974-
/** Tree that replaces a splice in pickled quotes.
975-
* It is only used when picking quotes (Will never be in a TASTy file).
977+
/** Tree that replaces a level 1 splices in pickled (level 0) quotes.
978+
* It is only used when picking quotes (will never be in a TASTy file).
979+
*
980+
* @param isTermHole If this hole is a term, otherwise it is a type hole.
981+
* @param idx The index of the hole in it's enclosing level 0 quote.
982+
* @param args The arguments of the splice to compute its content
983+
* @param content Lambda that computes the content of the hole. This tree is empty when in a quote pickle.
984+
* @param tpt Type of the hole
976985
*/
977-
case class Hole[-T >: Untyped](isTermHole: Boolean, idx: Int, args: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends Tree[T] {
986+
case class Hole[-T >: Untyped](isTermHole: Boolean, idx: Int, args: List[Tree[T]], content: Tree[T], tpt: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] {
978987
type ThisTree[-T >: Untyped] <: Hole[T]
979988
override def isTerm: Boolean = isTermHole
980989
override def isType: Boolean = !isTermHole
@@ -1330,6 +1339,10 @@ object Trees {
13301339
case tree: Thicket if (trees eq tree.trees) => tree
13311340
case _ => finalize(tree, untpd.Thicket(trees)(sourceFile(tree)))
13321341
}
1342+
def Hole(tree: Tree)(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole = tree match {
1343+
case tree: Hole if isTerm == tree.isTerm && idx == tree.idx && args.eq(tree.args) && content.eq(tree.content) && content.eq(tree.content) => tree
1344+
case _ => finalize(tree, untpd.Hole(isTerm, idx, args, content, tpt)(sourceFile(tree)))
1345+
}
13331346

13341347
// Copier methods with default arguments; these demand that the original tree
13351348
// is of the same class as the copy. We only include trees with more than 2 elements here.
@@ -1351,6 +1364,9 @@ object Trees {
13511364
TypeDef(tree: Tree)(name, rhs)
13521365
def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody)(using Context): Template =
13531366
Template(tree: Tree)(constr, parents, derived, self, body)
1367+
def Hole(tree: Hole)(isTerm: Boolean = tree.isTerm, idx: Int = tree.idx, args: List[Tree] = tree.args, content: Tree = tree.content, tpt: Tree = tree.tpt)(using Context): Hole =
1368+
Hole(tree: Tree)(isTerm, idx, args, content, tpt)
1369+
13541370
}
13551371

13561372
/** Hook to indicate that a transform of some subtree should be skipped */
@@ -1480,6 +1496,8 @@ object Trees {
14801496
case Thicket(trees) =>
14811497
val trees1 = transform(trees)
14821498
if (trees1 eq trees) tree else Thicket(trees1)
1499+
case tree @ Hole(_, _, args, content, tpt) =>
1500+
cpy.Hole(tree)(args = transform(args), content = transform(content), tpt = transform(tpt))
14831501
case _ =>
14841502
transformMoreCases(tree)
14851503
}
@@ -1619,8 +1637,8 @@ object Trees {
16191637
this(this(x, arg), annot)
16201638
case Thicket(ts) =>
16211639
this(x, ts)
1622-
case Hole(_, _, args) =>
1623-
this(x, args)
1640+
case Hole(_, _, args, content, tpt) =>
1641+
this(this(this(x, args), content), tpt)
16241642
case _ =>
16251643
foldMoreCases(x, tree)
16261644
}

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
373373
def Throw(expr: Tree)(using Context): Tree =
374374
ref(defn.throwMethod).appliedTo(expr)
375375

376+
def Hole(isTermHole: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole =
377+
ta.assignType(untpd.Hole(isTermHole, idx, args, content, tpt), tpt)
378+
376379
// ------ Making references ------------------------------------------------------
377380

378381
def prefixIsElidable(tp: NamedType)(using Context): Boolean = {
@@ -1507,10 +1510,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
15071510
* @param tpe the type of the elements of the resulting list.
15081511
*
15091512
*/
1510-
def mkList(trees: List[Tree], tpe: Tree)(using Context): Tree =
1513+
def mkList(trees: List[Tree], tpt: Tree)(using Context): Tree =
15111514
ref(defn.ListModule).select(nme.apply)
1512-
.appliedToTypeTree(tpe)
1513-
.appliedToVarargs(trees, tpe)
1515+
.appliedToTypeTree(tpt)
1516+
.appliedToVarargs(trees, tpt)
15141517

15151518

15161519
protected def FunProto(args: List[Tree], resType: Type)(using Context) =

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

+1
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
410410
def Export(expr: Tree, selectors: List[ImportSelector])(implicit src: SourceFile): Export = new Export(expr, selectors)
411411
def PackageDef(pid: RefTree, stats: List[Tree])(implicit src: SourceFile): PackageDef = new PackageDef(pid, stats)
412412
def Annotated(arg: Tree, annot: Tree)(implicit src: SourceFile): Annotated = new Annotated(arg, annot)
413+
def Hole(isTermHole: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(implicit src: SourceFile): Hole = new Hole(isTermHole, idx, args, content, tpt)
413414

414415
// ------ Additional creation methods for untyped only -----------------
415416

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

+36
Original file line numberDiff line numberDiff line change
@@ -785,10 +785,46 @@ class Definitions {
785785
@tu lazy val QuotedExprClass: ClassSymbol = requiredClass("scala.quoted.Expr")
786786

787787
@tu lazy val QuotesClass: ClassSymbol = requiredClass("scala.quoted.Quotes")
788+
@tu lazy val Quotes_reflect: Symbol = QuotesClass.requiredValue("reflect")
789+
@tu lazy val Quotes_reflect_asTerm: Symbol = Quotes_reflect.requiredMethod("asTerm")
790+
@tu lazy val Quotes_reflect_Apply: Symbol = Quotes_reflect.requiredValue("Apply")
791+
@tu lazy val Quotes_reflect_Apply_apply: Symbol = Quotes_reflect_Apply.requiredMethod(nme.apply)
792+
@tu lazy val Quotes_reflect_TypeApply: Symbol = Quotes_reflect.requiredValue("TypeApply")
793+
@tu lazy val Quotes_reflect_TypeApply_apply: Symbol = Quotes_reflect_TypeApply.requiredMethod(nme.apply)
794+
@tu lazy val Quotes_reflect_Assign: Symbol = Quotes_reflect.requiredValue("Assign")
795+
@tu lazy val Quotes_reflect_Assign_apply: Symbol = Quotes_reflect_Assign.requiredMethod(nme.apply)
796+
@tu lazy val Quotes_reflect_Inferred: Symbol = Quotes_reflect.requiredValue("Inferred")
797+
@tu lazy val Quotes_reflect_Inferred_apply: Symbol = Quotes_reflect_Inferred.requiredMethod(nme.apply)
798+
@tu lazy val Quotes_reflect_Literal: Symbol = Quotes_reflect.requiredValue("Literal")
799+
@tu lazy val Quotes_reflect_Literal_apply: Symbol = Quotes_reflect_Literal.requiredMethod(nme.apply)
800+
@tu lazy val Quotes_reflect_TreeMethods: Symbol = Quotes_reflect.requiredMethod("TreeMethods")
801+
@tu lazy val Quotes_reflect_TreeMethods_asExpr: Symbol = Quotes_reflect_TreeMethods.requiredMethod("asExpr")
802+
@tu lazy val Quotes_reflect_TypeRepr: Symbol = Quotes_reflect.requiredValue("TypeRepr")
803+
@tu lazy val Quotes_reflect_TypeRepr_of: Symbol = Quotes_reflect_TypeRepr.requiredMethod("of")
804+
@tu lazy val Quotes_reflect_TypeRepr_typeConstructorOf: Symbol = Quotes_reflect_TypeRepr.requiredMethod("typeConstructorOf")
805+
@tu lazy val Quotes_reflect_TypeReprMethods: Symbol = Quotes_reflect.requiredValue("TypeReprMethods")
806+
@tu lazy val Quotes_reflect_TypeReprMethods_asType: Symbol = Quotes_reflect_TypeReprMethods.requiredMethod("asType")
807+
@tu lazy val Quotes_reflect_TypeTreeType: Symbol = Quotes_reflect.requiredType("TypeTree")
808+
@tu lazy val Quotes_reflect_TermType: Symbol = Quotes_reflect.requiredType("Term")
809+
@tu lazy val Quotes_reflect_BooleanConstant: Symbol = Quotes_reflect.requiredValue("BooleanConstant")
810+
@tu lazy val Quotes_reflect_ByteConstant: Symbol = Quotes_reflect.requiredValue("ByteConstant")
811+
@tu lazy val Quotes_reflect_ShortConstant: Symbol = Quotes_reflect.requiredValue("ShortConstant")
812+
@tu lazy val Quotes_reflect_IntConstant: Symbol = Quotes_reflect.requiredValue("IntConstant")
813+
@tu lazy val Quotes_reflect_LongConstant: Symbol = Quotes_reflect.requiredValue("LongConstant")
814+
@tu lazy val Quotes_reflect_FloatConstant: Symbol = Quotes_reflect.requiredValue("FloatConstant")
815+
@tu lazy val Quotes_reflect_DoubleConstant: Symbol = Quotes_reflect.requiredValue("DoubleConstant")
816+
@tu lazy val Quotes_reflect_CharConstant: Symbol = Quotes_reflect.requiredValue("CharConstant")
817+
@tu lazy val Quotes_reflect_StringConstant: Symbol = Quotes_reflect.requiredValue("StringConstant")
818+
@tu lazy val Quotes_reflect_UnitConstant: Symbol = Quotes_reflect.requiredValue("UnitConstant")
819+
@tu lazy val Quotes_reflect_NullConstant: Symbol = Quotes_reflect.requiredValue("NullConstant")
820+
@tu lazy val Quotes_reflect_ClassOfConstant: Symbol = Quotes_reflect.requiredValue("ClassOfConstant")
821+
788822

789823
@tu lazy val QuoteUnpicklerClass: ClassSymbol = requiredClass("scala.quoted.runtime.QuoteUnpickler")
790824
@tu lazy val QuoteUnpickler_unpickleExpr: Symbol = QuoteUnpicklerClass.requiredMethod("unpickleExpr")
825+
@tu lazy val QuoteUnpickler_unpickleExprV2: Symbol = QuoteUnpicklerClass.requiredMethod("unpickleExprV2")
791826
@tu lazy val QuoteUnpickler_unpickleType: Symbol = QuoteUnpicklerClass.requiredMethod("unpickleType")
827+
@tu lazy val QuoteUnpickler_unpickleTypeV2: Symbol = QuoteUnpicklerClass.requiredMethod("unpickleTypeV2")
792828

793829
@tu lazy val QuoteMatchingClass: ClassSymbol = requiredClass("scala.quoted.runtime.QuoteMatching")
794830
@tu lazy val QuoteMatching_ExprMatch: Symbol = QuoteMatchingClass.requiredMethod("ExprMatch")

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ object Phases {
201201
private var mySbtExtractDependenciesPhase: Phase = _
202202
private var myPicklerPhase: Phase = _
203203
private var myInliningPhase: Phase = _
204-
private var myPickleQuotesPhase: Phase = _
204+
private var mySplicingPhase: Phase = _
205205
private var myFirstTransformPhase: Phase = _
206206
private var myCollectNullableFieldsPhase: Phase = _
207207
private var myRefChecksPhase: Phase = _
@@ -224,7 +224,7 @@ object Phases {
224224
final def sbtExtractDependenciesPhase: Phase = mySbtExtractDependenciesPhase
225225
final def picklerPhase: Phase = myPicklerPhase
226226
final def inliningPhase: Phase = myInliningPhase
227-
final def pickleQuotesPhase: Phase = myPickleQuotesPhase
227+
final def splicingPhase: Phase = mySplicingPhase
228228
final def firstTransformPhase: Phase = myFirstTransformPhase
229229
final def collectNullableFieldsPhase: Phase = myCollectNullableFieldsPhase
230230
final def refchecksPhase: Phase = myRefChecksPhase
@@ -250,7 +250,7 @@ object Phases {
250250
mySbtExtractDependenciesPhase = phaseOfClass(classOf[sbt.ExtractDependencies])
251251
myPicklerPhase = phaseOfClass(classOf[Pickler])
252252
myInliningPhase = phaseOfClass(classOf[Inlining])
253-
myPickleQuotesPhase = phaseOfClass(classOf[PickleQuotes])
253+
mySplicingPhase = phaseOfClass(classOf[Splicing])
254254
myFirstTransformPhase = phaseOfClass(classOf[FirstTransform])
255255
myCollectNullableFieldsPhase = phaseOfClass(classOf[CollectNullableFields])
256256
myRefChecksPhase = phaseOfClass(classOf[RefChecks])
@@ -426,7 +426,7 @@ object Phases {
426426
def sbtExtractDependenciesPhase(using Context): Phase = ctx.base.sbtExtractDependenciesPhase
427427
def picklerPhase(using Context): Phase = ctx.base.picklerPhase
428428
def inliningPhase(using Context): Phase = ctx.base.inliningPhase
429-
def pickleQuotesPhase(using Context): Phase = ctx.base.pickleQuotesPhase
429+
def splicingPhase(using Context): Phase = ctx.base.splicingPhase
430430
def firstTransformPhase(using Context): Phase = ctx.base.firstTransformPhase
431431
def refchecksPhase(using Context): Phase = ctx.base.refchecksPhase
432432
def elimRepeatedPhase(using Context): Phase = ctx.base.elimRepeatedPhase

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import dotty.tools.dotc.transform.PCPCheckAndHeal
88

99
object StagingContext {
1010

11-
/** A key to be used in a context property that tracks the quoteation level */
11+
/** A key to be used in a context property that tracks the quotation level */
1212
private val QuotationLevel = new Property.Key[Int]
1313

14-
/** A key to be used in a context property that tracks the quoteation stack.
15-
* Stack containing the Quotes references recieved by the surrounding quotes.
14+
/** A key to be used in a context property that tracks the quotation stack.
15+
* Stack containing the Quotes references received by the surrounding quotes.
1616
*/
1717
private val QuotesStack = new Property.Key[List[tpd.Tree]]
1818

@@ -26,7 +26,7 @@ object StagingContext {
2626
def quoteContext(using Context): Context =
2727
ctx.fresh.setProperty(QuotationLevel, level + 1)
2828

29-
/** Context with an incremented quotation level and pushes a refecence to a Quotes on the quote context stack */
29+
/** Context with an incremented quotation level and pushes a reference to a Quotes on the quote context stack */
3030
def pushQuotes(qctxRef: tpd.Tree)(using Context): Context =
3131
val old = ctx.property(QuotesStack).getOrElse(List.empty)
3232
ctx.fresh.setProperty(QuotationLevel, level + 1)
@@ -43,7 +43,7 @@ object StagingContext {
4343
ctx.property(TaggedTypes).get
4444

4545
/** Context with a decremented quotation level and pops the Some of top of the quote context stack or None if the stack is empty.
46-
* The quotation stack could be empty if we are in a top level splice or an eroneous splice directly witin a top level splice.
46+
* The quotation stack could be empty if we are in a top level splice or an erroneous splice directly within a top level splice.
4747
*/
4848
def popQuotes()(using Context): (Option[tpd.Tree], Context) =
4949
val ctx1 = ctx.fresh.setProperty(QuotationLevel, level - 1)

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

+3
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ object StdNames {
452452
val common: N = "common"
453453
val compiletime : N = "compiletime"
454454
val conforms_ : N = "$conforms"
455+
val contents: N = "contents"
455456
val copy: N = "copy"
456457
val currentMirror: N = "currentMirror"
457458
val create: N = "create"
@@ -505,6 +506,7 @@ object StdNames {
505506
val hash_ : N = "hash"
506507
val head: N = "head"
507508
val higherKinds: N = "higherKinds"
509+
val idx: N = "idx"
508510
val identity: N = "identity"
509511
val implicitConversions: N = "implicitConversions"
510512
val implicitly: N = "implicitly"
@@ -571,6 +573,7 @@ object StdNames {
571573
val productElementName: N = "productElementName"
572574
val productIterator: N = "productIterator"
573575
val productPrefix: N = "productPrefix"
576+
val quotes : N = "quotes"
574577
val raw_ : N = "raw"
575578
val refl: N = "refl"
576579
val reflect: N = "reflect"

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -635,11 +635,11 @@ class TreePickler(pickler: TastyPickler) {
635635
pickleTree(hi)
636636
pickleTree(alias)
637637
}
638-
case Hole(_, idx, args) =>
638+
case Hole(_, idx, args, _, tpt) =>
639639
writeByte(HOLE)
640640
withLength {
641641
writeNat(idx)
642-
pickleType(tree.tpe, richTypes = true)
642+
pickleType(tpt.tpe, richTypes = true)
643643
args.foreach(pickleTree)
644644
}
645645
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1284,7 +1284,7 @@ class TreeUnpickler(reader: TastyReader,
12841284
val idx = readNat()
12851285
val tpe = readType()
12861286
val args = until(end)(readTerm())
1287-
Hole(true, idx, args).withType(tpe)
1287+
Hole(true, idx, args, EmptyTree, TypeTree(tpe)).withType(tpe)
12881288
case _ =>
12891289
readPathTerm()
12901290
}
@@ -1318,7 +1318,7 @@ class TreeUnpickler(reader: TastyReader,
13181318
val idx = readNat()
13191319
val tpe = readType()
13201320
val args = until(end)(readTerm())
1321-
Hole(false, idx, args).withType(tpe)
1321+
Hole(false, idx, args, EmptyTree, TypeTree(tpe)).withType(tpe)
13221322
case _ =>
13231323
if (isTypeTreeTag(nextByte)) readTerm()
13241324
else {

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

+5-3
Original file line numberDiff line numberDiff line change
@@ -697,10 +697,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
697697
"Thicket {" ~~ toTextGlobal(trees, "\n") ~~ "}"
698698
case MacroTree(call) =>
699699
keywordStr("macro ") ~ toTextGlobal(call)
700-
case Hole(isTermHole, idx, args) =>
701-
val (prefix, postfix) = if isTermHole then ("{{{ ", " }}}") else ("[[[ ", " ]]]")
700+
case Hole(isTermHole, idx, args, content, tpt) =>
701+
val (prefix, postfix) = if isTermHole then ("{{{", "}}}") else ("[[[", "]]]")
702702
val argsText = toTextGlobal(args, ", ")
703-
prefix ~~ idx.toString ~~ "|" ~~ argsText ~~ postfix
703+
val contentText = toTextGlobal(content)
704+
val tptText = toTextGlobal(tpt)
705+
prefix ~~ idx.toString ~~ "|" ~~ tptText ~~ "|" ~~ argsText ~~ "|" ~~ contentText ~~ postfix
704706
case _ =>
705707
tree.fallbackToText(this)
706708
}

0 commit comments

Comments
 (0)