Skip to content

Commit 26c7fdc

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 0a2734b commit 26c7fdc

File tree

17 files changed

+143
-91
lines changed

17 files changed

+143
-91
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
@@ -905,6 +911,7 @@ object Trees {
905911
type CaseDef = Trees.CaseDef[T]
906912
type Labeled = Trees.Labeled[T]
907913
type Return = Trees.Return[T]
914+
type WhileDo = Trees.WhileDo[T]
908915
type Try = Trees.Try[T]
909916
type SeqLiteral = Trees.SeqLiteral[T]
910917
type JavaSeqLiteral = Trees.JavaSeqLiteral[T]
@@ -1060,6 +1067,10 @@ object Trees {
10601067
case tree: Return if (expr eq tree.expr) && (from eq tree.from) => tree
10611068
case _ => finalize(tree, untpd.Return(expr, from))
10621069
}
1070+
def WhileDo(tree: Tree)(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo = tree match {
1071+
case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree
1072+
case _ => finalize(tree, untpd.WhileDo(cond, body))
1073+
}
10631074
def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = tree match {
10641075
case tree: Try if (expr eq tree.expr) && (cases eq tree.cases) && (finalizer eq tree.finalizer) => tree
10651076
case _ => finalize(tree, untpd.Try(expr, cases, finalizer))
@@ -1234,6 +1245,8 @@ object Trees {
12341245
cpy.Labeled(tree)(transformSub(bind), transform(expr))
12351246
case Return(expr, from) =>
12361247
cpy.Return(tree)(transform(expr), transformSub(from))
1248+
case WhileDo(cond, body) =>
1249+
cpy.WhileDo(tree)(transform(cond), transform(body))
12371250
case Try(block, cases, finalizer) =>
12381251
cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer))
12391252
case SeqLiteral(elems, elemtpt) =>
@@ -1368,6 +1381,8 @@ object Trees {
13681381
this(this(x, bind), expr)
13691382
case Return(expr, from) =>
13701383
this(this(x, expr), from)
1384+
case WhileDo(cond, body) =>
1385+
this(this(x, cond), body)
13711386
case Try(block, handler, finalizer) =>
13721387
this(this(this(x, block), handler), finalizer)
13731388
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

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

612+
override def WhileDo(tree: Tree)(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo =
613+
ta.assignType(untpd.cpy.WhileDo(tree)(cond, body))
614+
609615
override def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = {
610616
val tree1 = untpd.cpy.Try(tree)(expr, cases, finalizer)
611617
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
@@ -282,6 +281,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
282281
def CaseDef(pat: Tree, guard: Tree, body: Tree): CaseDef = new CaseDef(pat, guard, body)
283282
def Labeled(bind: Bind, expr: Tree): Labeled = new Labeled(bind, expr)
284283
def Return(expr: Tree, from: Tree): Return = new Return(expr, from)
284+
def WhileDo(cond: Tree, body: Tree): WhileDo = new WhileDo(cond, body)
285285
def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree): Try = new Try(expr, cases, finalizer)
286286
def SeqLiteral(elems: List[Tree], elemtpt: Tree): SeqLiteral = new SeqLiteral(elems, elemtpt)
287287
def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt)
@@ -471,10 +471,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
471471
case tree: Quote if expr eq tree.expr => tree
472472
case _ => finalize(tree, untpd.Quote(expr))
473473
}
474-
def WhileDo(tree: Tree)(cond: Tree, body: Tree) = tree match {
475-
case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree
476-
case _ => finalize(tree, untpd.WhileDo(cond, body))
477-
}
478474
def DoWhile(tree: Tree)(body: Tree, cond: Tree) = tree match {
479475
case tree: DoWhile if (body eq tree.body) && (cond eq tree.cond) => tree
480476
case _ => finalize(tree, untpd.DoWhile(body, cond))
@@ -535,8 +531,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
535531
cpy.Throw(tree)(transform(expr))
536532
case Quote(expr) =>
537533
cpy.Quote(tree)(transform(expr))
538-
case WhileDo(cond, body) =>
539-
cpy.WhileDo(tree)(transform(cond), transform(body))
540534
case DoWhile(body, cond) =>
541535
cpy.DoWhile(tree)(transform(body), transform(cond))
542536
case ForYield(enums, expr) =>
@@ -586,8 +580,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
586580
this(x, expr)
587581
case Quote(expr) =>
588582
this(x, expr)
589-
case WhileDo(cond, body) =>
590-
this(this(x, cond), body)
591583
case DoWhile(body, cond) =>
592584
this(this(x, body), cond)
593585
case ForYield(enums, expr) =>

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

Lines changed: 41 additions & 38 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
@@ -244,7 +245,7 @@ Standard Section: "Comments" Comment*
244245
object TastyFormat {
245246

246247
final val header = Array(0x5C, 0xA1, 0xAB, 0x1F)
247-
val MajorVersion = 10
248+
val MajorVersion = 11
248249
val MinorVersion = 0
249250

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

434436
final val UNTYPEDSPLICE = 199
435437

@@ -604,6 +606,7 @@ object TastyFormat {
604606
case LAMBDA => "LAMBDA"
605607
case MATCH => "MATCH"
606608
case RETURN => "RETURN"
609+
case WHILE => "WHILE"
607610
case INLINED => "INLINED"
608611
case SELECTouter => "SELECTouter"
609612
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
@@ -429,6 +429,9 @@ class TreePickler(pickler: TastyPickler) {
429429
case Return(expr, from) =>
430430
writeByte(RETURN)
431431
withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) }
432+
case WhileDo(cond, body) =>
433+
writeByte(WHILE)
434+
withLength { pickleTree(cond); pickleTree(body) }
432435
case Try(block, cases, finalizer) =>
433436
writeByte(TRY)
434437
withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) }
@@ -783,6 +786,9 @@ class TreePickler(pickler: TastyPickler) {
783786
case Return(expr, from) =>
784787
writeByte(RETURN)
785788
withLength { pickleDummyRef(); pickleUnlessEmpty(expr) }
789+
case WhileDo(cond, body) =>
790+
writeByte(WHILE)
791+
withLength { pickleUntyped(cond); pickleUntyped(body) }
786792
case Try(block, cases, finalizer) =>
787793
writeByte(TRY)
788794
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
@@ -1076,6 +1076,8 @@ class TreeUnpickler(reader: TastyReader,
10761076
val from = readSymRef()
10771077
val expr = ifBefore(end)(readTerm(), EmptyTree)
10781078
Return(expr, Ident(from.termRef))
1079+
case WHILE =>
1080+
WhileDo(readTerm(), readTerm())
10791081
case TRY =>
10801082
Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree))
10811083
case SELECTouter =>
@@ -1322,6 +1324,8 @@ class TreeUnpickler(reader: TastyReader,
13221324
readNat()
13231325
val expr = ifBefore(end)(readUntyped(), untpd.EmptyTree)
13241326
untpd.Return(expr, untpd.EmptyTree)
1327+
case WHILE =>
1328+
untpd.WhileDo(readUntyped(), readUntyped())
13251329
case TRY =>
13261330
untpd.Try(readUntyped(), readCases(end), ifBefore(end)(readUntyped(), untpd.EmptyTree))
13271331
case BIND =>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
380380
changePrec(GlobalPrec) { keywordStr("return[") ~ toText(sym.name) ~ keywordStr("]") ~ optText(expr)(" " ~ _) }
381381
else
382382
changePrec(GlobalPrec) { keywordStr("return") ~ optText(expr)(" " ~ _) }
383+
case WhileDo(cond, body) =>
384+
changePrec(GlobalPrec) { keywordStr("while ") ~ toText(cond) ~ keywordStr(" do ") ~ toText(body) }
383385
case Try(expr, cases, finalizer) =>
384386
changePrec(GlobalPrec) {
385387
keywordStr("try ") ~ toText(expr) ~ optText(cases)(keywordStr(" catch ") ~ _) ~ optText(finalizer)(keywordStr(" finally ") ~ _)
@@ -518,8 +520,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
518520
"(" ~ toTextGlobal(t) ~ ")"
519521
case Tuple(ts) =>
520522
"(" ~ toTextGlobal(ts, ", ") ~ ")"
521-
case WhileDo(cond, body) =>
522-
changePrec(GlobalPrec) { keywordStr("while ") ~ toText(cond) ~ keywordStr(" do ") ~ toText(body) }
523523
case DoWhile(cond, body) =>
524524
changePrec(GlobalPrec) { keywordStr("do ") ~ toText(body) ~ keywordStr(" while ") ~ toText(cond) }
525525
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)