Skip to content

Reject failed inits #4434

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

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 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
13 changes: 5 additions & 8 deletions compiler/src/dotty/tools/repl/Rendering.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package dotty.tools
package repl

import java.io.{ StringWriter, PrintWriter }
import java.lang.{ ClassLoader, ExceptionInInitializerError }
import java.io.{ PrintWriter, StringWriter }
import java.lang.reflect.InvocationTargetException

import scala.util.control.NonFatal
import scala.util.Try

import dotc.core.Types._
import dotc.core.Contexts.Context
import dotc.core.Denotations.Denotation
import dotc.core.Flags
Expand Down Expand Up @@ -70,21 +68,20 @@ private[repl] class Rendering(compiler: ReplCompiler,
d.symbol.showUser

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

try {
Try {
val resultValue =
if (d.symbol.is(Flags.Lazy)) Some("<lazy>")
else valueOf(d.symbol)

resultValue.map(value => s"$dcl = $value")
}
catch { case ex: InvocationTargetException => Some(renderError(ex)) }
Copy link
Contributor

Choose a reason for hiding this comment

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

We should propagate any exception that is not an InvocationTargetException

}

/** Render the stack trace of the underlying exception */
private def renderError(ex: InvocationTargetException): String = {
def renderError(ex: InvocationTargetException): String = {
val cause = ex.getCause match {
case ex: ExceptionInInitializerError => ex.getCause
case ex => ex
Expand Down
46 changes: 30 additions & 16 deletions compiler/src/dotty/tools/repl/ReplDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@ package dotty.tools
package repl

import java.io.{ InputStream, PrintStream }
import java.lang.reflect.InvocationTargetException

import scala.annotation.tailrec

import dotc.reporting.MessageRendering
import dotc.reporting.diagnostic.MessageContainer
import dotc.ast.untpd
import dotc.ast.tpd
import dotc.interactive.{ SourceTree, Interactive }
import dotc.interactive.{ Interactive, SourceTree }
import dotc.core.Contexts.Context
import dotc.{ CompilationUnit, Run }
import dotc.{CompilationUnit, Run}
import dotc.core.Mode
import dotc.core.Flags._
import dotc.core.Types._
import dotc.core.StdNames._
import dotc.core.Names.Name
import dotc.core.NameOps._
import dotc.core.Symbols.{ Symbol, NoSymbol, defn }
import dotc.core.Symbols.{ NoSymbol, Symbol, defn }
import dotc.core.Denotations.Denotation
import dotc.core.Types.{ ExprType, ConstantType }
import dotc.core.Types.{ ConstantType, ExprType }
import dotc.core.NameKinds.SimpleNameKind
import dotc.config.CompilerCommand
import dotc.{ Compiler, Driver }
Expand Down Expand Up @@ -239,14 +239,15 @@ class ReplDriver(settings: Array[String],
// display warnings
displayErrors(newState.run.runContext.flushBufferedMessages())(newState)

displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports)
val afterRender = displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports)
afterRender.getOrElse(state)
}
}
)
}

/** Display definitions from `tree` */
private def displayDefinitions(tree: tpd.Tree, newestWrapper: Name)(implicit state: State): State = {
private def displayDefinitions(tree: tpd.Tree, newestWrapper: Name)(implicit state: State): Option[State] = {
implicit val ctx = state.run.runContext

def resAndUnit(denot: Denotation) = {
Expand Down Expand Up @@ -279,15 +280,20 @@ class ReplDriver(settings: Array[String],
val typeAliases =
info.bounds.hi.typeMembers.filter(_.symbol.info.isInstanceOf[TypeAlias])

(
typeAliases.map("// defined alias " + _.symbol.showUser) ++
defs.map(rendering.renderMethod) ++
vals.map(rendering.renderVal).flatten
).foreach(str => out.println(SyntaxHighlighting(str)))

state.copy(valIndex = state.valIndex - vals.filter(resAndUnit).length)
val (successes, failures) = vals.map(rendering.renderVal).partition(_.isSuccess)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should stop rendering vals after the first failure, like scalac REPL:

scala> val x = 1 / 0; println("1")
java.lang.ArithmeticException: / by zero
  ... 28 elided

In the example above, println("1") is not evaluated

Copy link
Contributor

Choose a reason for hiding this comment

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

And not render anything (e.g. aliases, methods) in case of failure

if (failures.isEmpty) {
val valRender = successes.flatMap(_.get)
(typeAliases.map("// defined alias " + _.symbol.showUser) ++
defs.map(rendering.renderMethod) ++
valRender
).foreach(str => out.println(SyntaxHighlighting(str)))
Some(state.copy(valIndex = state.valIndex - vals.filter(resAndUnit).length))
} else {
displayRenderFailures(failures.map(_.failed.get))
None
}
}
else state
else Some(state)

def isSyntheticCompanion(sym: Symbol) =
sym.is(Module) && sym.is(Synthetic)
Expand All @@ -313,7 +319,7 @@ class ReplDriver(settings: Array[String],
}
.getOrElse {
// user defined a trait/class/object, so no module needed
state
Some(state)
}
}
}
Expand Down Expand Up @@ -386,4 +392,12 @@ class ReplDriver(settings: Array[String],
errs.map(renderMessage(_)(state.run.runContext)).foreach(out.println)
state
}

private def displayRenderFailures(failures: Seq[Throwable]): Unit = {
failures.foreach(f => f match {
case (ite: InvocationTargetException) => out.println(SyntaxHighlighting(rendering.renderError(ite)))
case _ => out.println("<rendering error>")
})

}
}