Skip to content

Commit 0f182b4

Browse files
committed
Flatten top level block in REPL
This makes multi-line editing more convenient
1 parent 1b33a36 commit 0f182b4

File tree

4 files changed

+41
-11
lines changed

4 files changed

+41
-11
lines changed

compiler/src/dotty/tools/repl/ReplCompiler.scala

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,36 @@ class ReplCompiler extends Compiler {
7575

7676
implicit val ctx: Context = state.context
7777

78+
// If trees is of the form `{ def1; def2; def3 }` then `List(def1, def2, def3)`
79+
val flattened = trees match {
80+
case List(Block(stats, expr)) =>
81+
if (expr eq EmptyTree) stats // happens when expr is not an expression
82+
else stats :+ expr
83+
case _ =>
84+
trees
85+
}
86+
7887
var valIdx = state.valIndex
88+
val defs = new mutable.ListBuffer[Tree]
7989

80-
val defs = trees.flatMap {
90+
flattened.foreach {
8191
case expr @ Assign(id: Ident, _) =>
8292
// special case simple reassignment (e.g. x = 3)
8393
// in order to print the new value in the REPL
8494
val assignName = (id.name ++ str.REPL_ASSIGN_SUFFIX).toTermName
8595
val assign = ValDef(assignName, TypeTree(), id).withPos(expr.pos)
86-
List(expr, assign)
96+
defs += expr += assign
8797
case expr if expr.isTerm =>
8898
val resName = (str.REPL_RES_PREFIX + valIdx).toTermName
8999
valIdx += 1
90100
val vd = ValDef(resName, TypeTree(), expr).withPos(expr.pos)
91-
vd :: Nil
101+
defs += vd
92102
case other =>
93-
other :: Nil
103+
defs += other
94104
}
95105

96106
Definitions(
97-
defs,
107+
defs.toList,
98108
state.copy(
99109
objectIndex = state.objectIndex + (if (defs.isEmpty) 0 else 1),
100110
valIndex = valIdx

compiler/test-resources/repl/errmsgs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ scala> val x: List[Int] = "foo" :: List(1)
5353
| ^^^^^
5454
| Found: String("foo")
5555
| Required: Int
56-
scala> { def f: Int = g; val x: Int = 1; def g: Int = 5; }
57-
1 | { def f: Int = g; val x: Int = 1; def g: Int = 5; }
58-
| ^
59-
| g is a forward reference extending over the definition of x
6056
scala> while ((( foo ))) {}
6157
1 | while ((( foo ))) {}
6258
| ^^^
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
scala> { case class A(); def foo = 1; 2 }
2+
// defined case class A
3+
def foo: Int
4+
val res0: Int = 2
5+
6+
scala> foo
7+
val res1: Int = 1
8+
9+
scala> A()
10+
val res2: A = A()
11+
12+
scala> { def f: Int = g; def g: Int = 5 }
13+
def g: Int
14+
def f: Int
15+
16+
scala> f + g
17+
val res3: Int = 10
18+
19+
scala> { val x = 3; 4; val y = 5 }
20+
val x: Int = 3
21+
val res4: Int = 4
22+
val y: Int = 5

compiler/test/dotty/tools/repl/ReplCompilerTests.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import org.junit.{Ignore, Test}
77

88
class ReplCompilerTests extends ReplTest {
99

10+
private def lines() = storedOutput().split(EOL).toList
11+
1012
@Test def compileSingle = fromInitialState { implicit state =>
1113
run("def foo: 1 = 1")
1214
assertEquals("def foo: Int(1)", storedOutput().trim)
@@ -53,7 +55,7 @@ class ReplCompilerTests extends ReplTest {
5355
"val res1: Int = 20"
5456
)
5557

56-
assertEquals(expected, storedOutput().split(EOL).toList)
58+
assertEquals(expected, lines())
5759
}
5860

5961
@Test def testImportMutable =
@@ -124,6 +126,6 @@ class ReplCompilerTests extends ReplTest {
124126
)
125127

126128
run(source)
127-
assertEquals(expected, storedOutput().split(EOL).toList)
129+
assertEquals(expected, lines())
128130
}
129131
}

0 commit comments

Comments
 (0)