Skip to content

Commit 3bc7893

Browse files
committed
Promote WhileDo loops to typed trees.
They remain as such, without desugaring, until the back-end. We also use them to desugar `DoWhile` loops, instead of label-defs: do { body } while (cond) is now desugared as while { { body }; { cond } } () the inner blocks protecting the respective scopes of `body` and `cond` from each other. This is the second step towards getting rid of label-defs.
1 parent 20ad4a0 commit 3bc7893

File tree

17 files changed

+145
-93
lines changed

17 files changed

+145
-93
lines changed

compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
6363
type Throw = tpd.Apply
6464
type Labeled = tpd.Labeled
6565
type Return = tpd.Return
66+
type WhileDo = tpd.WhileDo
6667
type Block = tpd.Block
6768
type Typed = tpd.Typed
6869
type Match = tpd.Match
@@ -196,6 +197,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
196197
implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw])
197198
implicit val LabeledTag: ClassTag[Labeled] = ClassTag[Labeled](classOf[Labeled])
198199
implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return])
200+
implicit val WhileDoTag: ClassTag[WhileDo] = ClassTag[WhileDo](classOf[WhileDo])
199201
implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal])
200202
implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block])
201203
implicit val TypedTag: ClassTag[Typed] = ClassTag[Typed](classOf[Typed])
@@ -1088,6 +1090,11 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
10881090
def _2: Symbol = if (field.from.symbol.isLabel) field.from.symbol else NoSymbol
10891091
}
10901092

1093+
object WhileDo extends WhileDoDeconstructor {
1094+
def _1: Tree = field.cond
1095+
def _2: Tree = field.body
1096+
}
1097+
10911098
object Ident extends IdentDeconstructor {
10921099
def get = field.name
10931100
}

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

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -927,13 +927,6 @@ object desugar {
927927
/** Main desugaring method */
928928
def apply(tree: Tree)(implicit ctx: Context): Tree = {
929929

930-
/** { label def lname(): Unit = rhs; call }
931-
*/
932-
def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = {
933-
val ldef = DefDef(lname, Nil, ListOfNil, TypeTree(defn.UnitType), rhs).withFlags(Label | Synthetic)
934-
Block(ldef, call)
935-
}
936-
937930
/** Create tree for for-comprehension `<for (enums) do body>` or
938931
* `<for (enums) yield body>` where mapName and flatMapName are chosen
939932
* corresponding to whether this is a for-do or a for-yield.
@@ -1158,16 +1151,10 @@ object desugar {
11581151
case PrefixOp(op, t) =>
11591152
val nspace = if (ctx.mode.is(Mode.Type)) tpnme else nme
11601153
Select(t, nspace.UNARY_PREFIX ++ op.name)
1161-
case WhileDo(cond, body) =>
1162-
// { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
1163-
val call = Apply(Ident(nme.WHILE_PREFIX), Nil).withPos(tree.pos)
1164-
val rhs = If(cond, Block(body, call), unitLiteral)
1165-
labelDefAndCall(nme.WHILE_PREFIX, rhs, call)
11661154
case DoWhile(body, cond) =>
1167-
// { label def doWhile$(): Unit = { body; if (cond) doWhile$() } ; doWhile$() }
1168-
val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil).withPos(tree.pos)
1169-
val rhs = Block(body, If(cond, call, unitLiteral))
1170-
labelDefAndCall(nme.DO_WHILE_PREFIX, rhs, call)
1155+
// while ({ { body }; { cond } }) { () }
1156+
// the inner blocks are there to protect the scopes of body and cond from each other
1157+
WhileDo(Block(Block(Nil, body), Block(Nil, cond)), Literal(Constant(())))
11711158
case ForDo(enums, body) =>
11721159
makeFor(nme.foreach, nme.foreach, enums, body) orElse tree
11731160
case ForYield(enums, body) =>

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,12 @@ object Trees {
549549
type ThisTree[-T >: Untyped] = Return[T]
550550
}
551551

552+
/** while (cond) { body } */
553+
case class WhileDo[-T >: Untyped] private[ast] (cond: Tree[T], body: Tree[T])
554+
extends TermTree[T] {
555+
type ThisTree[-T >: Untyped] = WhileDo[T]
556+
}
557+
552558
/** try block catch handler finally finalizer
553559
*
554560
* Note: if the handler is a case block CASES of the form
@@ -911,6 +917,7 @@ object Trees {
911917
type CaseDef = Trees.CaseDef[T]
912918
type Labeled = Trees.Labeled[T]
913919
type Return = Trees.Return[T]
920+
type WhileDo = Trees.WhileDo[T]
914921
type Try = Trees.Try[T]
915922
type SeqLiteral = Trees.SeqLiteral[T]
916923
type JavaSeqLiteral = Trees.JavaSeqLiteral[T]
@@ -1067,6 +1074,10 @@ object Trees {
10671074
case tree: Return if (expr eq tree.expr) && (from eq tree.from) => tree
10681075
case _ => finalize(tree, untpd.Return(expr, from))
10691076
}
1077+
def WhileDo(tree: Tree)(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo = tree match {
1078+
case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree
1079+
case _ => finalize(tree, untpd.WhileDo(cond, body))
1080+
}
10701081
def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = tree match {
10711082
case tree: Try if (expr eq tree.expr) && (cases eq tree.cases) && (finalizer eq tree.finalizer) => tree
10721083
case _ => finalize(tree, untpd.Try(expr, cases, finalizer))
@@ -1245,6 +1256,8 @@ object Trees {
12451256
cpy.Labeled(tree)(transformSub(bind), transform(expr))
12461257
case Return(expr, from) =>
12471258
cpy.Return(tree)(transform(expr), transformSub(from))
1259+
case WhileDo(cond, body) =>
1260+
cpy.WhileDo(tree)(transform(cond), transform(body))
12481261
case Try(block, cases, finalizer) =>
12491262
cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer))
12501263
case SeqLiteral(elems, elemtpt) =>
@@ -1381,6 +1394,8 @@ object Trees {
13811394
this(this(x, bind), expr)
13821395
case Return(expr, from) =>
13831396
this(this(x, expr), from)
1397+
case WhileDo(cond, body) =>
1398+
this(this(x, cond), body)
13841399
case Try(block, handler, finalizer) =>
13851400
this(this(this(x, block), handler), finalizer)
13861401
case SeqLiteral(elems, elemtpt) =>

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
129129
def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return =
130130
ta.assignType(untpd.Return(expr, from))
131131

132+
def WhileDo(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo =
133+
ta.assignType(untpd.WhileDo(cond, body))
134+
132135
def Try(block: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try =
133136
ta.assignType(untpd.Try(block, cases, finalizer), block, cases)
134137

@@ -609,6 +612,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
609612
override def Return(tree: Tree)(expr: Tree, from: Tree)(implicit ctx: Context): Return =
610613
ta.assignType(untpd.cpy.Return(tree)(expr, from))
611614

615+
override def WhileDo(tree: Tree)(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo =
616+
ta.assignType(untpd.cpy.WhileDo(tree)(cond, body))
617+
612618
override def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = {
613619
val tree1 = untpd.cpy.Try(tree)(expr, cases, finalizer)
614620
tree match {

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
8585
}
8686
case class Throw(expr: Tree) extends TermTree
8787
case class Quote(expr: Tree) extends TermTree
88-
case class WhileDo(cond: Tree, body: Tree) extends TermTree
8988
case class DoWhile(body: Tree, cond: Tree) extends TermTree
9089
case class ForYield(enums: List[Tree], expr: Tree) extends TermTree
9190
case class ForDo(enums: List[Tree], body: Tree) extends TermTree
@@ -280,6 +279,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
280279
def CaseDef(pat: Tree, guard: Tree, body: Tree): CaseDef = new CaseDef(pat, guard, body)
281280
def Labeled(bind: Bind, expr: Tree): Labeled = new Labeled(bind, expr)
282281
def Return(expr: Tree, from: Tree): Return = new Return(expr, from)
282+
def WhileDo(cond: Tree, body: Tree): WhileDo = new WhileDo(cond, body)
283283
def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree): Try = new Try(expr, cases, finalizer)
284284
def SeqLiteral(elems: List[Tree], elemtpt: Tree): SeqLiteral = new SeqLiteral(elems, elemtpt)
285285
def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt)
@@ -470,10 +470,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
470470
case tree: Quote if expr eq tree.expr => tree
471471
case _ => finalize(tree, untpd.Quote(expr))
472472
}
473-
def WhileDo(tree: Tree)(cond: Tree, body: Tree) = tree match {
474-
case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree
475-
case _ => finalize(tree, untpd.WhileDo(cond, body))
476-
}
477473
def DoWhile(tree: Tree)(body: Tree, cond: Tree) = tree match {
478474
case tree: DoWhile if (body eq tree.body) && (cond eq tree.cond) => tree
479475
case _ => finalize(tree, untpd.DoWhile(body, cond))
@@ -534,8 +530,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
534530
cpy.Throw(tree)(transform(expr))
535531
case Quote(expr) =>
536532
cpy.Quote(tree)(transform(expr))
537-
case WhileDo(cond, body) =>
538-
cpy.WhileDo(tree)(transform(cond), transform(body))
539533
case DoWhile(body, cond) =>
540534
cpy.DoWhile(tree)(transform(body), transform(cond))
541535
case ForYield(enums, expr) =>
@@ -585,8 +579,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
585579
this(x, expr)
586580
case Quote(expr) =>
587581
this(x, expr)
588-
case WhileDo(cond, body) =>
589-
this(this(x, cond), body)
590582
case DoWhile(body, cond) =>
591583
this(this(x, body), cond)
592584
case ForYield(enums, expr) =>

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

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Standard-Section: "ASTs" TopLevelStat*
9191
MATCH Length sel_Term CaseDef*
9292
TRY Length expr_Term CaseDef* finalizer_Term?
9393
RETURN Length meth_ASTRef expr_Term?
94+
WHILE Length cond_Term body_Term
9495
REPEATED Length elem_Type elem_Term*
9596
SELECTouter Length levels_Nat qual_Term underlying_Type
9697
BIND Length boundName_NameRef patType_Type pat_Term
@@ -245,7 +246,7 @@ Standard Section: "Comments" Comment*
245246
object TastyFormat {
246247

247248
final val header = Array(0x5C, 0xA1, 0xAB, 0x1F)
248-
val MajorVersion = 10
249+
val MajorVersion = 11
249250
val MinorVersion = 0
250251

251252
/** Tags used to serialize names */
@@ -392,48 +393,49 @@ object TastyFormat {
392393
final val LAMBDA = 142
393394
final val MATCH = 143
394395
final val RETURN = 144
395-
final val TRY = 145
396-
final val INLINED = 146
397-
final val SELECTouter = 147
398-
final val REPEATED = 148
399-
final val BIND = 149
400-
final val ALTERNATIVE = 150
401-
final val UNAPPLY = 151
402-
final val ANNOTATEDtype = 152
403-
final val ANNOTATEDtpt = 153
404-
final val CASEDEF = 154
405-
final val TEMPLATE = 155
406-
final val SUPER = 156
407-
final val SUPERtype = 157
408-
final val REFINEDtype = 158
409-
final val REFINEDtpt = 159
410-
final val APPLIEDtype = 160
411-
final val APPLIEDtpt = 161
412-
final val TYPEBOUNDS = 162
413-
final val TYPEBOUNDStpt = 163
414-
final val ANDtype = 164
415-
final val ANDtpt = 165
416-
final val ORtype = 166
417-
final val ORtpt = 167
418-
final val POLYtype = 168
419-
final val TYPELAMBDAtype = 169
420-
final val LAMBDAtpt = 170
421-
final val PARAMtype = 171
422-
final val ANNOTATION = 172
423-
final val TERMREFin = 173
424-
final val TYPEREFin = 174
425-
final val OBJECTDEF = 175
426-
427-
// In binary: 101100EI
396+
final val WHILE = 145
397+
final val TRY = 146
398+
final val INLINED = 147
399+
final val SELECTouter = 148
400+
final val REPEATED = 149
401+
final val BIND = 150
402+
final val ALTERNATIVE = 151
403+
final val UNAPPLY = 152
404+
final val ANNOTATEDtype = 153
405+
final val ANNOTATEDtpt = 154
406+
final val CASEDEF = 155
407+
final val TEMPLATE = 156
408+
final val SUPER = 157
409+
final val SUPERtype = 158
410+
final val REFINEDtype = 159
411+
final val REFINEDtpt = 160
412+
final val APPLIEDtype = 161
413+
final val APPLIEDtpt = 162
414+
final val TYPEBOUNDS = 163
415+
final val TYPEBOUNDStpt = 164
416+
final val ANDtype = 165
417+
final val ANDtpt = 166
418+
final val ORtype = 167
419+
final val ORtpt = 168
420+
final val POLYtype = 169
421+
final val TYPELAMBDAtype = 170
422+
final val LAMBDAtpt = 171
423+
final val PARAMtype = 172
424+
final val ANNOTATION = 173
425+
final val TERMREFin = 174
426+
final val TYPEREFin = 175
427+
final val OBJECTDEF = 176
428+
429+
// In binary: 101101EI
428430
// I = implicit method type
429431
// E = erased method type
430-
final val METHODtype = 176
431-
final val IMPLICITMETHODtype = 177
432-
final val ERASEDMETHODtype = 178
433-
final val ERASEDIMPLICITMETHODtype = 179
432+
final val METHODtype = 180
433+
final val IMPLICITMETHODtype = 181
434+
final val ERASEDMETHODtype = 182
435+
final val ERASEDIMPLICITMETHODtype = 183
434436

435-
final val MATCHtype = 180
436-
final val MATCHtpt = 181
437+
final val MATCHtype = 190
438+
final val MATCHtpt = 191
437439

438440
final val UNTYPEDSPLICE = 199
439441

@@ -607,6 +609,7 @@ object TastyFormat {
607609
case LAMBDA => "LAMBDA"
608610
case MATCH => "MATCH"
609611
case RETURN => "RETURN"
612+
case WHILE => "WHILE"
610613
case INLINED => "INLINED"
611614
case SELECTouter => "SELECTouter"
612615
case TRY => "TRY"

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,9 @@ class TreePickler(pickler: TastyPickler) {
436436
case Return(expr, from) =>
437437
writeByte(RETURN)
438438
withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) }
439+
case WhileDo(cond, body) =>
440+
writeByte(WHILE)
441+
withLength { pickleTree(cond); pickleTree(body) }
439442
case Try(block, cases, finalizer) =>
440443
writeByte(TRY)
441444
withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) }
@@ -796,6 +799,9 @@ class TreePickler(pickler: TastyPickler) {
796799
case Return(expr, from) =>
797800
writeByte(RETURN)
798801
withLength { pickleDummyRef(); pickleUnlessEmpty(expr) }
802+
case WhileDo(cond, body) =>
803+
writeByte(WHILE)
804+
withLength { pickleUntyped(cond); pickleUntyped(body) }
799805
case Try(block, cases, finalizer) =>
800806
writeByte(TRY)
801807
withLength { pickleUntyped(block); cases.foreach(pickleUntyped); pickleUnlessEmpty(finalizer) }

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,8 @@ class TreeUnpickler(reader: TastyReader,
10801080
val from = readSymRef()
10811081
val expr = ifBefore(end)(readTerm(), EmptyTree)
10821082
Return(expr, Ident(from.termRef))
1083+
case WHILE =>
1084+
WhileDo(readTerm(), readTerm())
10831085
case TRY =>
10841086
Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree))
10851087
case SELECTouter =>
@@ -1331,6 +1333,8 @@ class TreeUnpickler(reader: TastyReader,
13311333
readNat()
13321334
val expr = ifBefore(end)(readUntyped(), untpd.EmptyTree)
13331335
untpd.Return(expr, untpd.EmptyTree)
1336+
case WHILE =>
1337+
untpd.WhileDo(readUntyped(), readUntyped())
13341338
case TRY =>
13351339
untpd.Try(readUntyped(), readCases(end), ifBefore(end)(readUntyped(), untpd.EmptyTree))
13361340
case BIND =>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
381381
changePrec(GlobalPrec) { keywordStr("return[") ~ toText(sym.name) ~ keywordStr("]") ~ optText(expr)(" " ~ _) }
382382
else
383383
changePrec(GlobalPrec) { keywordStr("return") ~ optText(expr)(" " ~ _) }
384+
case WhileDo(cond, body) =>
385+
changePrec(GlobalPrec) { keywordStr("while ") ~ toText(cond) ~ keywordStr(" do ") ~ toText(body) }
384386
case Try(expr, cases, finalizer) =>
385387
changePrec(GlobalPrec) {
386388
keywordStr("try ") ~ toText(expr) ~ optText(cases)(keywordStr(" catch ") ~ _) ~ optText(finalizer)(keywordStr(" finally ") ~ _)
@@ -524,8 +526,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
524526
"(" ~ toTextGlobal(t) ~ ")"
525527
case Tuple(ts) =>
526528
"(" ~ toTextGlobal(ts, ", ") ~ ")"
527-
case WhileDo(cond, body) =>
528-
changePrec(GlobalPrec) { keywordStr("while ") ~ toText(cond) ~ keywordStr(" do ") ~ toText(body) }
529529
case DoWhile(cond, body) =>
530530
changePrec(GlobalPrec) { keywordStr("do ") ~ toText(body) ~ keywordStr(" while ") ~ toText(cond) }
531531
case ForYield(enums, expr) =>

compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,6 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with TastyCoreImpl with He
278278

279279
object Block extends BlockExtractor {
280280
def unapply(x: Term)(implicit ctx: Context): Option[(List[Statement], Term)] = normalizedLoops(x) match {
281-
case Trees.Block(_, expr) if expr.symbol.is(Flags.Label) => None // while or doWhile loops
282281
case Trees.Block(stats, expr) => Some((stats, expr))
283282
case _ => None
284283
}
@@ -305,10 +304,10 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with TastyCoreImpl with He
305304
case _ => tree
306305
}
307306

308-
/** If it is the second statement of a loop or a closure. See: `normalizedLoops` */
307+
/** If it is the second statement of a closure. See: `normalizedLoops` */
309308
private def needsNormalization(tree: tpd.Tree)(implicit ctx: Context): Boolean = tree match {
310309
case _: tpd.Closure => true
311-
case _ => tree.symbol.is(Flags.Label)
310+
case _ => false
312311
}
313312
}
314313

@@ -375,26 +374,18 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with TastyCoreImpl with He
375374

376375
object While extends WhileExtractor {
377376
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match {
378-
case Trees.Block((ddef: tpd.DefDef) :: Nil, expr) if expr.symbol.is(Flags.Label) && expr.symbol.name == nme.WHILE_PREFIX =>
379-
val Trees.If(cond, Trees.Block(bodyStats, _), _) = ddef.rhs
380-
Some((cond, loopBody(bodyStats)))
377+
case x: tpd.WhileDo => Some((x.cond, x.body))
381378
case _ => None
382379
}
383380
}
384381

385382
object DoWhile extends DoWhileExtractor {
386383
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match {
387-
case Trees.Block((ddef: tpd.DefDef) :: Nil, expr) if expr.symbol.is(Flags.Label) && expr.symbol.name == nme.DO_WHILE_PREFIX =>
388-
val Trees.Block(bodyStats, Trees.If(cond, _, _)) = ddef.rhs
389-
Some((loopBody(bodyStats), cond))
384+
case Trees.WhileDo(Trees.Block(Trees.Block(Nil, body) :: Nil, Trees.Block(Nil, cond)), Trees.Literal(Constants.Constant(()))) =>
385+
Some((body, cond))
390386
case _ => None
391387
}
392388
}
393-
394-
private def loopBody(stats: List[tpd.Tree])(implicit ctx: Context): tpd.Tree = stats match {
395-
case body :: Nil => body
396-
case stats => tpd.Block(stats.init, stats.last)
397-
}
398389
}
399390

400391
def termAsParent(term: Term): Parent = term

0 commit comments

Comments
 (0)