Skip to content

REPL force module load as last resort #10723

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 1 commit into from
Dec 10, 2020
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
23 changes: 15 additions & 8 deletions compiler/src/dotty/tools/repl/Rendering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,25 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None) {
infoDiagnostic(d.symbol.showUser, d)

/** Render value definition result */
def renderVal(d: Denotation)(using Context): Option[Diagnostic] = {
def renderVal(d: Denotation)(using Context): Option[Diagnostic] =
val dcl = d.symbol.showUser

try {
try
if (d.symbol.is(Flags.Lazy)) Some(infoDiagnostic(dcl, d))
else valueOf(d.symbol).map(value => infoDiagnostic(s"$dcl = $value", d))
}
catch { case ex: InvocationTargetException => Some(infoDiagnostic(renderError(ex), d)) }
}

/** Render the stack trace of the underlying exception */
private def renderError(ex: InvocationTargetException): String = {
catch case ex: InvocationTargetException => Some(infoDiagnostic(renderError(ex), d))
end renderVal

/** Force module initialization in the absence of members. */
def forceModule(sym: Symbol)(using Context): Seq[Diagnostic] =
def load() =
val objectName = sym.fullName.encode.toString
val resObj: Class[?] = Class.forName(objectName, true, classLoader())
Nil
try load() catch case e: ExceptionInInitializerError => List(infoDiagnostic(renderError(e), sym.denot))

/** Render the stack trace of the underlying exception. */
private def renderError(ex: InvocationTargetException | ExceptionInInitializerError): String = {
val cause = ex.getCause match {
case ex: ExceptionInInitializerError => ex.getCause
case ex => ex
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/repl/ReplDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,9 @@ class ReplDriver(settings: Array[String],
defs.map(rendering.renderMethod) ++
vals.flatMap(rendering.renderVal)

(state.copy(valIndex = state.valIndex - vals.count(resAndUnit)), formattedMembers)
val diagnostics = if formattedMembers.isEmpty then rendering.forceModule(symbol) else formattedMembers

(state.copy(valIndex = state.valIndex - vals.count(resAndUnit)), diagnostics)
}
else (state, Seq.empty)

Expand Down
16 changes: 16 additions & 0 deletions compiler/test/dotty/tools/repl/ReplCompilerTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,22 @@ class ReplCompilerTests extends ReplTest {
run("val a: 1 | 0 = 1")
assertEquals("val a: 1 | 0 = 1", storedOutput().trim)
}

@Test def `i10214 must show classic MatchError` = fromInitialState { implicit state =>
run("val 1 = 2")
assertEquals("scala.MatchError: 2 (of class java.lang.Integer)", storedOutput().linesIterator.next())
}
@Test def `i10214 must show useful regex MatchError` =
fromInitialState { implicit state =>
run("""val r = raw"\d+".r""")
} andThen { implicit state =>
run("""val r() = "abc"""")
assertEquals("scala.MatchError: abc (of class java.lang.String)", storedOutput().linesIterator.drop(2).next())
}
@Test def `i10214 must show MatchError on literal type` = fromInitialState { implicit state =>
run("val (x: 1) = 2")
assertEquals("scala.MatchError: 2 (of class java.lang.Integer)", storedOutput().linesIterator.next())
}
}

object ReplCompilerTests {
Expand Down