Skip to content

Promote WhileDo loops to typed trees. #5113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
type Throw = tpd.Apply
type Labeled = tpd.Labeled
type Return = tpd.Return
type WhileDo = tpd.WhileDo
type Block = tpd.Block
type Typed = tpd.Typed
type Match = tpd.Match
Expand Down Expand Up @@ -196,6 +197,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw])
implicit val LabeledTag: ClassTag[Labeled] = ClassTag[Labeled](classOf[Labeled])
implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return])
implicit val WhileDoTag: ClassTag[WhileDo] = ClassTag[WhileDo](classOf[WhileDo])
implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal])
implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block])
implicit val TypedTag: ClassTag[Typed] = ClassTag[Typed](classOf[Typed])
Expand Down Expand Up @@ -1088,6 +1090,11 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
def _2: Symbol = if (field.from.symbol.isLabel) field.from.symbol else NoSymbol
}

object WhileDo extends WhileDoDeconstructor {
def _1: Tree = field.cond
def _2: Tree = field.body
}

object Ident extends IdentDeconstructor {
def get = field.name
}
Expand Down
19 changes: 3 additions & 16 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -927,13 +927,6 @@ object desugar {
/** Main desugaring method */
def apply(tree: Tree)(implicit ctx: Context): Tree = {

/** { label def lname(): Unit = rhs; call }
*/
def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = {
val ldef = DefDef(lname, Nil, ListOfNil, TypeTree(defn.UnitType), rhs).withFlags(Label | Synthetic)
Block(ldef, call)
}

/** Create tree for for-comprehension `<for (enums) do body>` or
* `<for (enums) yield body>` where mapName and flatMapName are chosen
* corresponding to whether this is a for-do or a for-yield.
Expand Down Expand Up @@ -1158,16 +1151,10 @@ object desugar {
case PrefixOp(op, t) =>
val nspace = if (ctx.mode.is(Mode.Type)) tpnme else nme
Select(t, nspace.UNARY_PREFIX ++ op.name)
case WhileDo(cond, body) =>
// { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
val call = Apply(Ident(nme.WHILE_PREFIX), Nil).withPos(tree.pos)
val rhs = If(cond, Block(body, call), unitLiteral)
labelDefAndCall(nme.WHILE_PREFIX, rhs, call)
case DoWhile(body, cond) =>
// { label def doWhile$(): Unit = { body; if (cond) doWhile$() } ; doWhile$() }
val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil).withPos(tree.pos)
val rhs = Block(body, If(cond, call, unitLiteral))
labelDefAndCall(nme.DO_WHILE_PREFIX, rhs, call)
// while ({ { body }; { cond } }) { () }
// the inner blocks are there to protect the scopes of body and cond from each other
WhileDo(Block(Block(Nil, body), Block(Nil, cond)), Literal(Constant(())))
case ForDo(enums, body) =>
makeFor(nme.foreach, nme.foreach, enums, body) orElse tree
case ForYield(enums, body) =>
Expand Down
15 changes: 15 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,12 @@ object Trees {
type ThisTree[-T >: Untyped] = Return[T]
}

/** while (cond) { body } */
case class WhileDo[-T >: Untyped] private[ast] (cond: Tree[T], body: Tree[T])
extends TermTree[T] {
type ThisTree[-T >: Untyped] = WhileDo[T]
}

/** try block catch handler finally finalizer
*
* Note: if the handler is a case block CASES of the form
Expand Down Expand Up @@ -911,6 +917,7 @@ object Trees {
type CaseDef = Trees.CaseDef[T]
type Labeled = Trees.Labeled[T]
type Return = Trees.Return[T]
type WhileDo = Trees.WhileDo[T]
type Try = Trees.Try[T]
type SeqLiteral = Trees.SeqLiteral[T]
type JavaSeqLiteral = Trees.JavaSeqLiteral[T]
Expand Down Expand Up @@ -1067,6 +1074,10 @@ object Trees {
case tree: Return if (expr eq tree.expr) && (from eq tree.from) => tree
case _ => finalize(tree, untpd.Return(expr, from))
}
def WhileDo(tree: Tree)(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo = tree match {
case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree
case _ => finalize(tree, untpd.WhileDo(cond, body))
}
def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = tree match {
case tree: Try if (expr eq tree.expr) && (cases eq tree.cases) && (finalizer eq tree.finalizer) => tree
case _ => finalize(tree, untpd.Try(expr, cases, finalizer))
Expand Down Expand Up @@ -1245,6 +1256,8 @@ object Trees {
cpy.Labeled(tree)(transformSub(bind), transform(expr))
case Return(expr, from) =>
cpy.Return(tree)(transform(expr), transformSub(from))
case WhileDo(cond, body) =>
cpy.WhileDo(tree)(transform(cond), transform(body))
case Try(block, cases, finalizer) =>
cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer))
case SeqLiteral(elems, elemtpt) =>
Expand Down Expand Up @@ -1381,6 +1394,8 @@ object Trees {
this(this(x, bind), expr)
case Return(expr, from) =>
this(this(x, expr), from)
case WhileDo(cond, body) =>
this(this(x, cond), body)
case Try(block, handler, finalizer) =>
this(this(this(x, block), handler), finalizer)
case SeqLiteral(elems, elemtpt) =>
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return =
ta.assignType(untpd.Return(expr, from))

def WhileDo(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo =
ta.assignType(untpd.WhileDo(cond, body))

def Try(block: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try =
ta.assignType(untpd.Try(block, cases, finalizer), block, cases)

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

override def WhileDo(tree: Tree)(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo =
ta.assignType(untpd.cpy.WhileDo(tree)(cond, body))

override def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = {
val tree1 = untpd.cpy.Try(tree)(expr, cases, finalizer)
tree match {
Expand Down
10 changes: 1 addition & 9 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
}
case class Throw(expr: Tree) extends TermTree
case class Quote(expr: Tree) extends TermTree
case class WhileDo(cond: Tree, body: Tree) extends TermTree
case class DoWhile(body: Tree, cond: Tree) extends TermTree
case class ForYield(enums: List[Tree], expr: Tree) extends TermTree
case class ForDo(enums: List[Tree], body: Tree) extends TermTree
Expand Down Expand Up @@ -280,6 +279,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def CaseDef(pat: Tree, guard: Tree, body: Tree): CaseDef = new CaseDef(pat, guard, body)
def Labeled(bind: Bind, expr: Tree): Labeled = new Labeled(bind, expr)
def Return(expr: Tree, from: Tree): Return = new Return(expr, from)
def WhileDo(cond: Tree, body: Tree): WhileDo = new WhileDo(cond, body)
def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree): Try = new Try(expr, cases, finalizer)
def SeqLiteral(elems: List[Tree], elemtpt: Tree): SeqLiteral = new SeqLiteral(elems, elemtpt)
def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt)
Expand Down Expand Up @@ -470,10 +470,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case tree: Quote if expr eq tree.expr => tree
case _ => finalize(tree, untpd.Quote(expr))
}
def WhileDo(tree: Tree)(cond: Tree, body: Tree) = tree match {
case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree
case _ => finalize(tree, untpd.WhileDo(cond, body))
}
def DoWhile(tree: Tree)(body: Tree, cond: Tree) = tree match {
case tree: DoWhile if (body eq tree.body) && (cond eq tree.cond) => tree
case _ => finalize(tree, untpd.DoWhile(body, cond))
Expand Down Expand Up @@ -534,8 +530,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
cpy.Throw(tree)(transform(expr))
case Quote(expr) =>
cpy.Quote(tree)(transform(expr))
case WhileDo(cond, body) =>
cpy.WhileDo(tree)(transform(cond), transform(body))
case DoWhile(body, cond) =>
cpy.DoWhile(tree)(transform(body), transform(cond))
case ForYield(enums, expr) =>
Expand Down Expand Up @@ -585,8 +579,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
this(x, expr)
case Quote(expr) =>
this(x, expr)
case WhileDo(cond, body) =>
this(this(x, cond), body)
case DoWhile(body, cond) =>
this(this(x, body), cond)
case ForYield(enums, expr) =>
Expand Down
83 changes: 43 additions & 40 deletions compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ Standard-Section: "ASTs" TopLevelStat*
MATCH Length sel_Term CaseDef*
TRY Length expr_Term CaseDef* finalizer_Term?
RETURN Length meth_ASTRef expr_Term?
WHILE Length cond_Term body_Term
REPEATED Length elem_Type elem_Term*
SELECTouter Length levels_Nat qual_Term underlying_Type
BIND Length boundName_NameRef patType_Type pat_Term
Expand Down Expand Up @@ -245,7 +246,7 @@ Standard Section: "Comments" Comment*
object TastyFormat {

final val header = Array(0x5C, 0xA1, 0xAB, 0x1F)
val MajorVersion = 10
val MajorVersion = 11
val MinorVersion = 0

/** Tags used to serialize names */
Expand Down Expand Up @@ -392,48 +393,49 @@ object TastyFormat {
final val LAMBDA = 142
final val MATCH = 143
final val RETURN = 144
final val TRY = 145
final val INLINED = 146
final val SELECTouter = 147
final val REPEATED = 148
final val BIND = 149
final val ALTERNATIVE = 150
final val UNAPPLY = 151
final val ANNOTATEDtype = 152
final val ANNOTATEDtpt = 153
final val CASEDEF = 154
final val TEMPLATE = 155
final val SUPER = 156
final val SUPERtype = 157
final val REFINEDtype = 158
final val REFINEDtpt = 159
final val APPLIEDtype = 160
final val APPLIEDtpt = 161
final val TYPEBOUNDS = 162
final val TYPEBOUNDStpt = 163
final val ANDtype = 164
final val ANDtpt = 165
final val ORtype = 166
final val ORtpt = 167
final val POLYtype = 168
final val TYPELAMBDAtype = 169
final val LAMBDAtpt = 170
final val PARAMtype = 171
final val ANNOTATION = 172
final val TERMREFin = 173
final val TYPEREFin = 174
final val OBJECTDEF = 175

// In binary: 101100EI
final val WHILE = 145
final val TRY = 146
final val INLINED = 147
final val SELECTouter = 148
final val REPEATED = 149
final val BIND = 150
final val ALTERNATIVE = 151
final val UNAPPLY = 152
final val ANNOTATEDtype = 153
final val ANNOTATEDtpt = 154
final val CASEDEF = 155
final val TEMPLATE = 156
final val SUPER = 157
final val SUPERtype = 158
final val REFINEDtype = 159
final val REFINEDtpt = 160
final val APPLIEDtype = 161
final val APPLIEDtpt = 162
final val TYPEBOUNDS = 163
final val TYPEBOUNDStpt = 164
final val ANDtype = 165
final val ANDtpt = 166
final val ORtype = 167
final val ORtpt = 168
final val POLYtype = 169
final val TYPELAMBDAtype = 170
final val LAMBDAtpt = 171
final val PARAMtype = 172
final val ANNOTATION = 173
final val TERMREFin = 174
final val TYPEREFin = 175
final val OBJECTDEF = 176

// In binary: 101101EI
// I = implicit method type
// E = erased method type
final val METHODtype = 176
final val IMPLICITMETHODtype = 177
final val ERASEDMETHODtype = 178
final val ERASEDIMPLICITMETHODtype = 179
final val METHODtype = 180
final val IMPLICITMETHODtype = 181
final val ERASEDMETHODtype = 182
final val ERASEDIMPLICITMETHODtype = 183

final val MATCHtype = 180
final val MATCHtpt = 181
final val MATCHtype = 190
final val MATCHtpt = 191

final val UNTYPEDSPLICE = 199

Expand Down Expand Up @@ -607,6 +609,7 @@ object TastyFormat {
case LAMBDA => "LAMBDA"
case MATCH => "MATCH"
case RETURN => "RETURN"
case WHILE => "WHILE"
case INLINED => "INLINED"
case SELECTouter => "SELECTouter"
case TRY => "TRY"
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ class TreePickler(pickler: TastyPickler) {
case Return(expr, from) =>
writeByte(RETURN)
withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) }
case WhileDo(cond, body) =>
writeByte(WHILE)
withLength { pickleTree(cond); pickleTree(body) }
case Try(block, cases, finalizer) =>
writeByte(TRY)
withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) }
Expand Down Expand Up @@ -796,6 +799,9 @@ class TreePickler(pickler: TastyPickler) {
case Return(expr, from) =>
writeByte(RETURN)
withLength { pickleDummyRef(); pickleUnlessEmpty(expr) }
case WhileDo(cond, body) =>
writeByte(WHILE)
withLength { pickleUntyped(cond); pickleUntyped(body) }
case Try(block, cases, finalizer) =>
writeByte(TRY)
withLength { pickleUntyped(block); cases.foreach(pickleUntyped); pickleUnlessEmpty(finalizer) }
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,8 @@ class TreeUnpickler(reader: TastyReader,
val from = readSymRef()
val expr = ifBefore(end)(readTerm(), EmptyTree)
Return(expr, Ident(from.termRef))
case WHILE =>
WhileDo(readTerm(), readTerm())
case TRY =>
Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree))
case SELECTouter =>
Expand Down Expand Up @@ -1331,6 +1333,8 @@ class TreeUnpickler(reader: TastyReader,
readNat()
val expr = ifBefore(end)(readUntyped(), untpd.EmptyTree)
untpd.Return(expr, untpd.EmptyTree)
case WHILE =>
untpd.WhileDo(readUntyped(), readUntyped())
case TRY =>
untpd.Try(readUntyped(), readCases(end), ifBefore(end)(readUntyped(), untpd.EmptyTree))
case BIND =>
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
changePrec(GlobalPrec) { keywordStr("return[") ~ toText(sym.name) ~ keywordStr("]") ~ optText(expr)(" " ~ _) }
else
changePrec(GlobalPrec) { keywordStr("return") ~ optText(expr)(" " ~ _) }
case WhileDo(cond, body) =>
changePrec(GlobalPrec) { keywordStr("while ") ~ toText(cond) ~ keywordStr(" do ") ~ toText(body) }
case Try(expr, cases, finalizer) =>
changePrec(GlobalPrec) {
keywordStr("try ") ~ toText(expr) ~ optText(cases)(keywordStr(" catch ") ~ _) ~ optText(finalizer)(keywordStr(" finally ") ~ _)
Expand Down Expand Up @@ -524,8 +526,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
"(" ~ toTextGlobal(t) ~ ")"
case Tuple(ts) =>
"(" ~ toTextGlobal(ts, ", ") ~ ")"
case WhileDo(cond, body) =>
changePrec(GlobalPrec) { keywordStr("while ") ~ toText(cond) ~ keywordStr(" do ") ~ toText(body) }
case DoWhile(cond, body) =>
changePrec(GlobalPrec) { keywordStr("do ") ~ toText(body) ~ keywordStr(" while ") ~ toText(cond) }
case ForYield(enums, expr) =>
Expand Down
23 changes: 3 additions & 20 deletions compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,6 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with TastyCoreImpl with He

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

/** If it is the second statement of a loop or a closure. See: `normalizedLoops` */
/** If it is the second statement of a closure. See: `normalizedLoops` */
private def needsNormalization(tree: tpd.Tree)(implicit ctx: Context): Boolean = tree match {
case _: tpd.Closure => true
case _ => tree.symbol.is(Flags.Label)
case _ => false
}
}

Expand Down Expand Up @@ -375,26 +374,10 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with TastyCoreImpl with He

object While extends WhileExtractor {
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match {
case Trees.Block((ddef: tpd.DefDef) :: Nil, expr) if expr.symbol.is(Flags.Label) && expr.symbol.name == nme.WHILE_PREFIX =>
val Trees.If(cond, Trees.Block(bodyStats, _), _) = ddef.rhs
Some((cond, loopBody(bodyStats)))
case x: tpd.WhileDo => Some((x.cond, x.body))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this case we should check that this is not a do while.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe it would be better to remove the do while extractor and place that condition in the decompiler.

case _ => None
}
}

object DoWhile extends DoWhileExtractor {
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match {
case Trees.Block((ddef: tpd.DefDef) :: Nil, expr) if expr.symbol.is(Flags.Label) && expr.symbol.name == nme.DO_WHILE_PREFIX =>
val Trees.Block(bodyStats, Trees.If(cond, _, _)) = ddef.rhs
Some((loopBody(bodyStats), cond))
case _ => None
}
}

private def loopBody(stats: List[tpd.Tree])(implicit ctx: Context): tpd.Tree = stats match {
case body :: Nil => body
case stats => tpd.Block(stats.init, stats.last)
}
}

def termAsParent(term: Term): Parent = term
Expand Down
Loading