Skip to content

Commit 9db9d9b

Browse files
committed
Fix decompilation of while loops
1 parent f1140e9 commit 9db9d9b

File tree

3 files changed

+92
-43
lines changed

3 files changed

+92
-43
lines changed

library/src/scala/tasty/util/ShowSourceCode.scala

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,39 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
145145
this
146146
}
147147

148+
case While(cond, stats) =>
149+
this += "while ("
150+
printTree(cond)
151+
this += ") "
152+
stats match {
153+
case stat :: Nil =>
154+
printTree(stat)
155+
case stats =>
156+
this += "{"
157+
indented {
158+
this += lineBreak()
159+
printTrees(stats, lineBreak())
160+
}
161+
this += lineBreak() += "}"
162+
}
163+
164+
case DoWhile(stats, cond) =>
165+
this += "do "
166+
stats match {
167+
case stat :: Nil =>
168+
printTree(stat)
169+
case stats =>
170+
this += "{"
171+
indented {
172+
this += lineBreak()
173+
printTrees(stats, lineBreak())
174+
}
175+
this += lineBreak() += "}"
176+
}
177+
this += " while ("
178+
printTree(cond)
179+
this += ")"
180+
148181
case ddef@DefDef(name, targs, argss, tpt, rhs) =>
149182
val flags = ddef.flags
150183
if (flags.isOverride) sb.append("override ")
@@ -225,7 +258,14 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
225258
this += " = "
226259
printTree(rhs)
227260

228-
case Term.Block(stats, expr) =>
261+
case Term.Block(stats0, expr) =>
262+
def isLoopEntryPoint(tree: Tree): Boolean = tree match {
263+
case Term.Apply(Term.Ident("while$" | "doWhile$"), _) => true
264+
case _ => false
265+
}
266+
267+
val stats = stats0.filterNot(isLoopEntryPoint)
268+
229269
expr match {
230270
case Term.Lambda(_, _) =>
231271
// Decompile lambda from { def annon$(...) = ...; closure(annon$, ...)}
@@ -235,31 +275,22 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
235275
this += " => "
236276
printTree(rhs)
237277
this += ")"
238-
239-
case Term.Apply(Term.Ident("while$"), _) =>
240-
val DefDef("while$", _, _, _, Some(Term.If(cond, Term.Block(body :: Nil, _), _))) = stats.head
241-
this += "while ("
242-
printTree(cond)
243-
this += ") "
244-
printTree(body)
245-
246-
case Term.Apply(Term.Ident("doWhile$"), _) =>
247-
val DefDef("doWhile$", _, _, _, Some(Term.Block(List(body), Term.If(cond, _, _)))) = stats.head
248-
this += "do "
249-
printTree(body)
250-
this += " while ("
251-
printTree(cond)
252-
this += ")"
253-
278+
case expr if isLoopEntryPoint(expr) && stats.size == 1 =>
279+
// Print { def while$() = ...; while$() }
280+
// as while (...) ...
281+
// instead of { while (...) ... }
282+
printTree(stats.head)
254283
case _ =>
255284
this += "{"
256285
indented {
257286
if (!stats.isEmpty) {
258287
this += lineBreak()
259288
printTrees(stats, lineBreak())
260289
}
261-
this += lineBreak()
262-
printTree(expr)
290+
if (!isLoopEntryPoint(expr)) {
291+
this += lineBreak()
292+
printTree(expr)
293+
}
263294
}
264295
this += lineBreak() += "}"
265296
}
@@ -719,6 +750,20 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
719750
}
720751
}
721752

753+
private object While {
754+
def unapply(arg: Tree)(implicit ctx: Context): Option[(Term, List[Statement])] = arg match {
755+
case DefDef("while$", _, _, _, Some(Term.If(cond, Term.Block(bodyStats, _), _))) => Some((cond, bodyStats))
756+
case _ => None
757+
}
758+
}
759+
760+
private object DoWhile {
761+
def unapply(arg: Tree)(implicit ctx: Context): Option[(List[Statement], Term)] = arg match {
762+
case DefDef("doWhile$", _, _, _, Some(Term.Block(body, Term.If(cond, _, _)))) => Some((body, cond))
763+
case _ => None
764+
}
765+
}
766+
722767
// TODO Provide some of these in scala.tasty.Tasty.scala and implement them using checks on symbols for performance
723768
private object Types {
724769

tests/run/quote-inline-function.check

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
Normal function
22
{
3-
var i: Int = 0
4-
val j: Int = 5
5-
<label> def while$(): Unit =
6-
if i.<(j) then
7-
{
8-
val x$1: Int = i
9-
f.apply(x$1)
10-
i = i.+(1)
11-
while$()
12-
}
13-
else ()
14-
while$()
3+
var i: scala.Int = 0
4+
val j: scala.Int = 5
5+
while (i.<(j)) {
6+
val x$1: scala.Int = i
7+
f.apply(x$1)
8+
i = i.+(1)
9+
}
10+
do {
11+
val x$2: scala.Int = i
12+
f.apply(x$2)
13+
i = i.+(1)
14+
} while (i.<(j))
1515
}
1616

1717
By name function
1818
{
19-
var i: Int = 0
20-
val j: Int = 5
21-
<label> def while$(): Unit =
22-
if i.<(j) then
23-
{
24-
val x$1: Int = i
25-
scala.Predef.println(x$1)
26-
i = i.+(1)
27-
while$()
28-
}
29-
else ()
30-
while$()
19+
var i: scala.Int = 0
20+
val j: scala.Int = 5
21+
while (i.<(j)) {
22+
val x$1: scala.Int = i
23+
scala.Predef.println(x$1)
24+
i = i.+(1)
25+
}
26+
do {
27+
val x$2: scala.Int = i
28+
scala.Predef.println(x$2)
29+
i = i.+(1)
30+
} while (i.<(j))
3131
}

tests/run/quote-inline-function/quoted_1.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ object Macros {
1515
~f.apply('(i))
1616
i += 1
1717
}
18+
do {
19+
~f.apply('(i))
20+
i += 1
21+
} while (i < j)
1822
}
1923
res.show.toExpr
2024
}

0 commit comments

Comments
 (0)