Skip to content

Commit a886cd4

Browse files
authored
Merge pull request #3314 from dotty-staging/fix-#3305
Fix #3305 and #3309
2 parents f24c36d + 3144646 commit a886cd4

File tree

8 files changed

+88
-16
lines changed

8 files changed

+88
-16
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package repl
44
import dotc.reporting.diagnostic.MessageContainer
55
import dotc.core.Contexts.Context
66
import dotc.parsing.Parsers.Parser
7+
import dotc.parsing.Tokens
78
import dotc.util.SourceFile
89
import dotc.ast.untpd
910
import dotc.reporting._
@@ -97,6 +98,12 @@ object ParseResult {
9798

9899
@sharable private[this] val CommandExtract = """(:[\S]+)\s*(.*)""".r
99100

101+
private def parseStats(parser: Parser): List[untpd.Tree] = {
102+
val stats = parser.blockStatSeq()
103+
parser.accept(Tokens.EOF)
104+
stats
105+
}
106+
100107
/** Extract a `ParseResult` from the string `sourceCode` */
101108
def apply(sourceCode: String)(implicit ctx: Context): ParseResult =
102109
sourceCode match {
@@ -114,7 +121,7 @@ object ParseResult {
114121
val source = new SourceFile("<console>", sourceCode.toCharArray)
115122
val parser = new Parser(source)
116123

117-
val (_, stats) = parser.templateStatSeq()
124+
val stats = parseStats(parser)
118125

119126
if (ctx.reporter.hasErrors) {
120127
SyntaxErrors(sourceCode,
@@ -140,7 +147,7 @@ object ParseResult {
140147
reporter.withIncompleteHandler(_ => _ => needsMore = true) {
141148
val source = new SourceFile("<console>", sourceCode.toCharArray)
142149
val parser = new Parser(source)(ctx.fresh.setReporter(reporter))
143-
parser.templateStatSeq()
150+
parseStats(parser)
144151
!reporter.hasErrors && needsMore
145152
}
146153
}

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package dotty.tools
22
package repl
33

4-
import java.lang.ClassLoader
4+
import java.io.{ StringWriter, PrintWriter }
5+
import java.lang.{ ClassLoader, ExceptionInInitializerError }
6+
import java.lang.reflect.InvocationTargetException
57

68
import scala.util.control.NonFatal
79

@@ -70,10 +72,26 @@ private[repl] class Rendering(compiler: ReplCompiler,
7072
/** Render value definition result */
7173
def renderVal(d: Denotation)(implicit ctx: Context): Option[String] = {
7274
val dcl = d.symbol.showUser
73-
val resultValue =
74-
if (d.symbol.is(Flags.Lazy)) Some("<lazy>")
75-
else valueOf(d.symbol)
7675

77-
resultValue.map(value => s"$dcl = $value")
76+
try {
77+
val resultValue =
78+
if (d.symbol.is(Flags.Lazy)) Some("<lazy>")
79+
else valueOf(d.symbol)
80+
81+
resultValue.map(value => s"$dcl = $value")
82+
}
83+
catch { case ex: InvocationTargetException => Some(renderError(ex)) }
84+
}
85+
86+
/** Render the stack trace of the underlying exception */
87+
private def renderError(ex: InvocationTargetException): String = {
88+
val cause = ex.getCause match {
89+
case ex: ExceptionInInitializerError => ex.getCause
90+
case ex => ex
91+
}
92+
val sw = new StringWriter()
93+
val pw = new PrintWriter(sw)
94+
cause.printStackTrace(pw)
95+
sw.toString
7896
}
7997
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler {
146146
* }
147147
* ```
148148
*/
149-
def wrapped(defs: Definitions): untpd.PackageDef = {
149+
def wrapped(defs: Definitions, sourceCode: String): untpd.PackageDef = {
150150
import untpd._
151151

152152
implicit val ctx: Context = defs.state.run.runContext
@@ -156,7 +156,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler {
156156
List(
157157
ModuleDef(objectName(defs.state), tmpl)
158158
.withMods(new Modifiers(Module | Final))
159-
.withPos(Position(defs.stats.head.pos.start, defs.stats.last.pos.end))
159+
.withPos(Position(0, sourceCode.length))
160160
)
161161
}
162162

@@ -170,7 +170,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler {
170170

171171
def createUnit(defs: Definitions, sourceCode: String): Result[CompilationUnit] = {
172172
val unit = new CompilationUnit(new SourceFile(objectName(defs.state).toString, sourceCode))
173-
unit.untpdTree = wrapped(defs)
173+
unit.untpdTree = wrapped(defs, sourceCode)
174174
unit.result
175175
}
176176

@@ -238,7 +238,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler {
238238
PackageDef(Ident(nme.EMPTY_PACKAGE),
239239
TypeDef("EvaluateExpr".toTypeName, tmpl)
240240
.withMods(new Modifiers(Final))
241-
.withPos(Position(trees.head.pos.start, trees.last.pos.end)) :: Nil
241+
.withPos(Position(0, expr.length)) :: Nil
242242
)
243243
}
244244

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ class ReplDriver(settings: Array[String],
186186

187187
private def interpret(res: ParseResult)(implicit state: State): State =
188188
res match {
189-
case parsed: Parsed =>
189+
case parsed: Parsed if parsed.trees.nonEmpty =>
190190
compile(parsed)
191191
.withHistory(parsed.sourceCode :: state.history)
192192
.newRun(compiler, rootCtx)
@@ -195,9 +195,13 @@ class ReplDriver(settings: Array[String],
195195
displayErrors(errs)
196196
state.withHistory(src :: state.history)
197197

198-
case Newline | SigKill => state
199-
200198
case cmd: Command => interpretCommand(cmd)
199+
200+
case SigKill => // TODO
201+
state
202+
203+
case _ => // new line, empty tree
204+
state
201205
}
202206

203207
/** Compile `parsed` trees and evolve `state` in accordance */

compiler/test-resources/repl/parsing

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
scala> ;
2+
scala> ;;
3+
scala> 1; 2
4+
val res0: Int = 1
5+
val res1: Int = 2
6+
scala> 1;
7+
val res2: Int = 1
8+
scala> 1;; 2
9+
val res3: Int = 1
10+
val res4: Int = 2
11+
scala> }
12+
1 | }
13+
| ^
14+
| eof expected, but '}' found

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,27 @@ class ReplCompilerTests extends ReplTest {
9292
storedOutput()
9393
)
9494
}
95+
96+
@Test def i3305: Unit = {
97+
fromInitialState { implicit s =>
98+
compile("null.toString")
99+
storedOutput().startsWith("java.lang.NullPointerException")
100+
}
101+
102+
fromInitialState { implicit s =>
103+
compile("def foo: Int = 1 + foo; foo")
104+
storedOutput().startsWith("def foo: Int\njava.lang.StackOverflowError")
105+
}
106+
107+
fromInitialState { implicit s =>
108+
compile("""throw new IllegalArgumentException("Hello")""")
109+
storedOutput().startsWith("java.lang.IllegalArgumentException: Hello")
110+
}
111+
112+
// FIXME
113+
// fromInitialState { implicit s =>
114+
// compile("val (x, y) = null")
115+
// storedOutput().startsWith("scala.MatchError: null")
116+
// }
117+
}
95118
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import scala.io.Source
1111

1212
import dotc.reporting.MessageRendering
1313

14-
/** Runs all tests contained in `/repl/test-resources/scripts` */
14+
/** Runs all tests contained in `compiler/test-resources/repl/` */
1515
class ScriptedTests extends ReplTest with MessageRendering {
1616

1717
private def scripts(path: String): Array[JFile] = {
@@ -44,7 +44,7 @@ class ScriptedTests extends ReplTest with MessageRendering {
4444
def evaluate(state: State, input: String, prompt: String) =
4545
try {
4646
val nstate = run(input.drop(prompt.length))(state)
47-
val out = input + "\n" + stripColor(storedOutput())
47+
val out = input + "\n" + storedOutput()
4848
(out, nstate)
4949
}
5050
catch {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,10 @@ class TabcompleteTests extends ReplTest {
5252
assert(tabComplete(src2).suggestions.nonEmpty)
5353
}
5454
}
55+
56+
@Test def i3309: Unit =
57+
fromInitialState { implicit s =>
58+
List("\"", "#", ")", "=", "'", "¨", "£", ".", ":", ",", ";", "@", "}", "[", "]")
59+
.foreach(src => assertTrue(tabComplete(src).suggestions.isEmpty))
60+
}
5561
}

0 commit comments

Comments
 (0)