Skip to content

Commit 95e9557

Browse files
committed
Add type argument list to the Hole tree
1 parent 304df79 commit 95e9557

File tree

11 files changed

+48
-37
lines changed

11 files changed

+48
-37
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,12 @@ class TreeTypeMap(
146146
val bind1 = tmap.transformSub(bind)
147147
val expr1 = tmap.transform(expr)
148148
cpy.Labeled(labeled)(bind1, expr1)
149-
case tree @ Hole(_, _, args, content, tpt) =>
149+
case tree @ Hole(_, _, targs, args, content, tpt) =>
150+
val targs1 = targs.mapConserve(transform)
150151
val args1 = args.mapConserve(transform)
151152
val content1 = transform(content)
152153
val tpt1 = transform(tpt)
153-
cpy.Hole(tree)(args = args1, content = content1, tpt = tpt1)
154+
cpy.Hole(tree)(targs = targs1, args = args1, content = content1, tpt = tpt1)
154155
case tree1 =>
155156
super.transform(tree1)
156157
}

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

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -978,13 +978,20 @@ object Trees {
978978
/** Tree that replaces a level 1 splices in pickled (level 0) quotes.
979979
* It is only used when picking quotes (will never be in a TASTy file).
980980
*
981+
* Hole created by this compile separate the targs from the args. Holes
982+
* generated with 3.0-3.3 contain all type args and targs in any order in
983+
* a single list. For backwards compatibility we read holes from tasty as
984+
* if they had no targs and have only args. Therefore the args may contain
985+
* type trees.
986+
*
981987
* @param isTermHole If this hole is a term, otherwise it is a type hole.
982988
* @param idx The index of the hole in it's enclosing level 0 quote.
983-
* @param args The arguments of the splice to compute its content
984-
* @param content Lambda that computes the content of the hole. This tree is empty when in a quote pickle.
989+
* @param targs The type arguments of the splice to compute its content
990+
* @param args The term (or type) arguments of the splice to compute its content
985991
* @param tpt Type of the hole
992+
* @param content Lambda that computes the content of the hole. This tree is empty when in a quote pickle.
986993
*/
987-
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] {
994+
case class Hole[+T <: Untyped](isTermHole: Boolean, idx: Int, targs: List[Tree[T]], args: List[Tree[T]], content: Tree[T], tpt: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] {
988995
type ThisTree[+T <: Untyped] <: Hole[T]
989996
override def isTerm: Boolean = isTermHole
990997
override def isType: Boolean = !isTermHole
@@ -1337,9 +1344,9 @@ object Trees {
13371344
case tree: Thicket if (trees eq tree.trees) => tree
13381345
case _ => finalize(tree, untpd.Thicket(trees)(sourceFile(tree)))
13391346
}
1340-
def Hole(tree: Tree)(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole = tree match {
1341-
case tree: Hole if isTerm == tree.isTerm && idx == tree.idx && args.eq(tree.args) && content.eq(tree.content) && content.eq(tree.content) => tree
1342-
case _ => finalize(tree, untpd.Hole(isTerm, idx, args, content, tpt)(sourceFile(tree)))
1347+
def Hole(tree: Tree)(isTerm: Boolean, idx: Int, targs: List[Tree], args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole = tree match {
1348+
case tree: Hole if isTerm == tree.isTerm && idx == tree.idx && targs.eq(tree.targs) && args.eq(tree.args) && content.eq(tree.content) && content.eq(tree.content) => tree
1349+
case _ => finalize(tree, untpd.Hole(isTerm, idx, targs, args, content, tpt)(sourceFile(tree)))
13431350
}
13441351

13451352
// Copier methods with default arguments; these demand that the original tree
@@ -1362,8 +1369,8 @@ object Trees {
13621369
TypeDef(tree: Tree)(name, rhs)
13631370
def Template(tree: Template)(using Context)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody): Template =
13641371
Template(tree: Tree)(constr, parents, derived, self, body)
1365-
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 =
1366-
Hole(tree: Tree)(isTerm, idx, args, content, tpt)
1372+
def Hole(tree: Hole)(isTerm: Boolean = tree.isTerm, idx: Int = tree.idx, targs: List[Tree] = tree.targs, args: List[Tree] = tree.args, content: Tree = tree.content, tpt: Tree = tree.tpt)(using Context): Hole =
1373+
Hole(tree: Tree)(isTerm, idx, targs, args, content, tpt)
13671374

13681375
}
13691376

@@ -1494,8 +1501,8 @@ object Trees {
14941501
case Thicket(trees) =>
14951502
val trees1 = transform(trees)
14961503
if (trees1 eq trees) tree else Thicket(trees1)
1497-
case tree @ Hole(_, _, args, content, tpt) =>
1498-
cpy.Hole(tree)(args = transform(args), content = transform(content), tpt = transform(tpt))
1504+
case tree @ Hole(_, _, targs, args, content, tpt) =>
1505+
cpy.Hole(tree)(targs = transform(targs), args = transform(args), content = transform(content), tpt = transform(tpt))
14991506
case _ =>
15001507
transformMoreCases(tree)
15011508
}
@@ -1635,8 +1642,8 @@ object Trees {
16351642
this(this(x, arg), annot)
16361643
case Thicket(ts) =>
16371644
this(x, ts)
1638-
case Hole(_, _, args, content, tpt) =>
1639-
this(this(this(x, args), content), tpt)
1645+
case Hole(_, _, targs, args, content, tpt) =>
1646+
this(this(this(this(x, targs), args), content), tpt)
16401647
case _ =>
16411648
foldMoreCases(x, tree)
16421649
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
391391
def Throw(expr: Tree)(using Context): Tree =
392392
ref(defn.throwMethod).appliedTo(expr)
393393

394-
def Hole(isTermHole: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole =
395-
ta.assignType(untpd.Hole(isTermHole, idx, args, content, tpt), tpt)
394+
def Hole(isTermHole: Boolean, idx: Int, targs: List[Tree], args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole =
395+
ta.assignType(untpd.Hole(isTermHole, idx, targs, args, content, tpt), tpt)
396396

397397
// ------ Making references ------------------------------------------------------
398398

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
426426
def Export(expr: Tree, selectors: List[ImportSelector])(implicit src: SourceFile): Export = new Export(expr, selectors)
427427
def PackageDef(pid: RefTree, stats: List[Tree])(implicit src: SourceFile): PackageDef = new PackageDef(pid, stats)
428428
def Annotated(arg: Tree, annot: Tree)(implicit src: SourceFile): Annotated = new Annotated(arg, annot)
429-
def Hole(isTermHole: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(implicit src: SourceFile): Hole = new Hole(isTermHole, idx, args, content, tpt)
429+
def Hole(isTermHole: Boolean, idx: Int, targs: List[Tree], args: List[Tree], content: Tree, tpt: Tree)(implicit src: SourceFile): Hole = new Hole(isTermHole, idx, targs, args, content, tpt)
430430

431431
// ------ Additional creation methods for untyped only -----------------
432432

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,11 +665,12 @@ class TreePickler(pickler: TastyPickler) {
665665
pickleTree(hi)
666666
pickleTree(alias)
667667
}
668-
case Hole(_, idx, args, _, tpt) =>
668+
case Hole(_, idx, targs, args, _, tpt) =>
669669
writeByte(HOLE)
670670
withLength {
671671
writeNat(idx)
672672
pickleType(tpt.tpe, richTypes = true)
673+
targs.foreach(pickleTree)
673674
args.foreach(pickleTree)
674675
}
675676
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,8 +1438,9 @@ class TreeUnpickler(reader: TastyReader,
14381438
case HOLE =>
14391439
val idx = readNat()
14401440
val tpe = readType()
1441+
val targs = Nil // TODO read tags seprately from args
14411442
val args = until(end)(readTerm())
1442-
Hole(true, idx, args, EmptyTree, TypeTree(tpe)).withType(tpe)
1443+
Hole(true, idx, targs, args, EmptyTree, TypeTree(tpe)).withType(tpe)
14431444
case _ =>
14441445
readPathTerm()
14451446
}
@@ -1472,8 +1473,9 @@ class TreeUnpickler(reader: TastyReader,
14721473
val end = readEnd()
14731474
val idx = readNat()
14741475
val tpe = readType()
1476+
val targs = Nil // TODO read tags seprately from args
14751477
val args = until(end)(readTerm())
1476-
Hole(false, idx, args, EmptyTree, TypeTree(tpe)).withType(tpe)
1478+
Hole(false, idx, targs, args, EmptyTree, TypeTree(tpe)).withType(tpe)
14771479
case _ =>
14781480
if (isTypeTreeTag(nextByte)) readTerm()
14791481
else {

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -724,12 +724,13 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
724724
"Thicket {" ~~ toTextGlobal(trees, "\n") ~~ "}"
725725
case MacroTree(call) =>
726726
keywordStr("macro ") ~ toTextGlobal(call)
727-
case Hole(isTermHole, idx, args, content, tpt) =>
727+
case Hole(isTermHole, idx, targs, args, content, tpt) =>
728728
val (prefix, postfix) = if isTermHole then ("{{{", "}}}") else ("[[[", "]]]")
729-
val argsText = toTextGlobal(args, ", ")
730-
val contentText = toTextGlobal(content)
729+
val targsText = ("[" ~ toTextGlobal(targs, ", ") ~ "]").provided(targs.nonEmpty)
730+
val argsText = ("(" ~ toTextGlobal(args, ", ") ~ ")").provided(args.nonEmpty)
731731
val tptText = toTextGlobal(tpt)
732-
prefix ~~ idx.toString ~~ "|" ~~ tptText ~~ "|" ~~ argsText ~~ "|" ~~ contentText ~~ postfix
732+
val contentText = ("|" ~~ toTextGlobal(content)).provided(content ne EmptyTree)
733+
prefix ~~ idx.toString ~ targsText ~ argsText ~ ":" ~~ tptText ~~ contentText ~~ postfix
733734
case CapturingTypeTree(refs, parent) =>
734735
parent match
735736
case ImpureByNameTypeTree(bntpt) =>

compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ object PickledQuotes {
100100
private def spliceTerms(tree: Tree, typeHole: TypeHole, termHole: ExprHole)(using Context): Tree = {
101101
def evaluateHoles = new TreeMap {
102102
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
103-
case Hole(isTermHole, idx, args, _, _) =>
103+
case Hole(isTermHole, idx, targs, args, _, _) =>
104104
inContext(SpliceScope.contextWithNewSpliceScope(tree.sourcePos)) {
105105
if isTermHole then
106106
val quotedExpr = termHole match
107107
case ExprHole.V1(evalHole) =>
108-
evalHole.nn.apply(idx, reifyExprHoleV1Args(args), QuotesImpl())
108+
evalHole.nn.apply(idx, reifyExprHoleV1Args(targs ::: args), QuotesImpl())
109109
case ExprHole.V2(evalHole) =>
110-
evalHole.nn.apply(idx, reifyExprHoleV2Args(args), QuotesImpl())
110+
evalHole.nn.apply(idx, reifyExprHoleV2Args(targs ::: args), QuotesImpl())
111111

112112
val filled = PickledQuotes.quotedExprToTree(quotedExpr)
113113

@@ -165,15 +165,15 @@ object PickledQuotes {
165165
val tree = typeHole match
166166
case TypeHole.V1(evalHole) =>
167167
tdef.rhs match
168-
case TypeBoundsTree(_, Hole(_, idx, args, _, _), _) =>
168+
case TypeBoundsTree(_, Hole(_, idx, targs, args, _, _), _) =>
169169
// To keep for backwards compatibility. In some older version holes where created in the bounds.
170-
val quotedType = evalHole.nn.apply(idx, reifyTypeHoleArgs(args))
170+
val quotedType = evalHole.nn.apply(idx, reifyTypeHoleArgs(targs ::: args))
171171
PickledQuotes.quotedTypeToTree(quotedType)
172172
case TypeBoundsTree(_, tpt, _) =>
173173
// To keep for backwards compatibility. In some older version we missed the creation of some holes.
174174
tpt
175175
case TypeHole.V2(types) =>
176-
val Hole(_, idx, _, _, _) = tdef.rhs: @unchecked
176+
val Hole(_, idx, _, _, _, _) = tdef.rhs: @unchecked
177177
PickledQuotes.quotedTypeToTree(types.nn.apply(idx))
178178
(tdef.symbol, tree.tpe)
179179
}.toMap

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class PickleQuotes extends MacroTransform {
126126
private val contents = List.newBuilder[Tree]
127127
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
128128
tree match
129-
case tree @ Hole(isTerm, _, _, content, _) =>
129+
case tree @ Hole(isTerm, _, _, _, content, _) =>
130130
if !content.isEmpty then
131131
contents += content
132132
val holeType =

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class Splicing extends MacroTransform:
133133
case None =>
134134
val holeIdx = numHoles
135135
numHoles += 1
136-
val hole = tpd.Hole(false, holeIdx, Nil, ref(qual), TypeTree(tp))
136+
val hole = tpd.Hole(false, holeIdx, Nil, Nil, ref(qual), TypeTree(tp))
137137
typeHoles.put(qual.symbol, hole)
138138
hole
139139
cpy.TypeDef(tree)(rhs = hole)
@@ -200,15 +200,14 @@ class Splicing extends MacroTransform:
200200
val newTree = transform(tree)
201201
val (typeRefs, typeBindings) = typeBindingMap.values.toList.unzip
202202
val (termRefs, termBindings) = termBindingMap.values.toList.unzip
203-
val refs = typeRefs ::: termRefs
204203
val bindings = typeBindings ::: termBindings
205204
val bindingsTypes = bindings.map(_.termRef.widenTermRefExpr)
206205
val methType = MethodType(bindingsTypes, newTree.tpe)
207206
val meth = newSymbol(spliceOwner, nme.ANON_FUN, Synthetic | Method, methType)
208207
val ddef = DefDef(meth, List(bindings), newTree.tpe, newTree.changeOwner(ctx.owner, meth))
209208
val fnType = defn.FunctionType(bindings.size, isContextual = false).appliedTo(bindingsTypes :+ newTree.tpe)
210209
val closure = Block(ddef :: Nil, Closure(Nil, ref(meth), TypeTree(fnType)))
211-
tpd.Hole(true, holeIdx, refs, closure, TypeTree(tpe))
210+
tpd.Hole(true, holeIdx, typeRefs, termRefs, closure, TypeTree(tpe))
212211

213212
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
214213
tree match

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,19 +653,19 @@ object TreeChecker {
653653
super.typedPackageDef(tree)
654654

655655
override def typedHole(tree: untpd.Hole, pt: Type)(using Context): Tree = {
656-
val tree1 @ Hole(isTermHole, _, args, content, tpt) = super.typedHole(tree, pt): @unchecked
656+
val tree1 @ Hole(isTermHole, _, targs, args, content, tpt) = super.typedHole(tree, pt): @unchecked
657657

658658
// Check that we only add the captured type `T` instead of a more complex type like `List[T]`.
659659
// If we have `F[T]` with captured `F` and `T`, we should list `F` and `T` separately in the args.
660-
for arg <- args do
660+
for arg <- (targs ::: args) do // TODO check targs and terms separately
661661
assert(arg.isTerm || arg.tpe.isInstanceOf[TypeRef], "Expected TypeRef in Hole type args but got: " + arg.tpe)
662662

663663
// Check result type of the hole
664664
if isTermHole then assert(tpt.typeOpt <:< pt)
665665
else assert(tpt.typeOpt =:= pt)
666666

667667
// Check that the types of the args conform to the types of the contents of the hole
668-
val argQuotedTypes = args.map { arg =>
668+
val argQuotedTypes = (targs ::: args).map { arg =>
669669
if arg.isTerm then
670670
val tpe = arg.typeOpt.widenTermRefExpr match
671671
case _: MethodicType =>

0 commit comments

Comments
 (0)