From f448b6d9ba064d1c56d2c992107dc9e4aa8ae6ca Mon Sep 17 00:00:00 2001 From: Ankit Soni Date: Mon, 30 Apr 2018 12:28:14 -0700 Subject: [PATCH 1/6] render with try --- compiler/src/dotty/tools/repl/Rendering.scala | 32 +++++++++--- .../src/dotty/tools/repl/ReplDriver.scala | 51 ++++++++++++------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/compiler/src/dotty/tools/repl/Rendering.scala b/compiler/src/dotty/tools/repl/Rendering.scala index 5dff8890d336..90c5555f97ed 100644 --- a/compiler/src/dotty/tools/repl/Rendering.scala +++ b/compiler/src/dotty/tools/repl/Rendering.scala @@ -1,12 +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.{ClassLoader, ExceptionInInitializerError} import java.lang.reflect.InvocationTargetException import scala.util.control.NonFatal - import dotc.core.Types._ import dotc.core.Contexts.Context import dotc.core.Denotations.Denotation @@ -14,6 +13,8 @@ import dotc.core.Flags import dotc.core.Symbols.Symbol import dotc.core.StdNames.str +import scala.util.{Failure, Success, Try} + /** This rendering object uses `ClassLoader`s to accomplish crossing the 4th * wall (i.e. fetching back values from the compiled class files put into a * specific class loader capable of loading from memory) and rendering them. @@ -70,21 +71,38 @@ 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): Either[String,Option[String]] = { + val dcl = d.symbol.showUser + + Try { + val resultValue = + if (d.symbol.is(Flags.Lazy)) Some("") + else valueOf(d.symbol) + + resultValue.map(value => s"$dcl = $value") + } match { + case Success(s) => Right(s) + case Failure(ex: InvocationTargetException) => Left(renderError(ex)) + case Failure(e) => Left("") + } + + } + + def renderVal2(d: Denotation)(implicit ctx: Context): Try[Option[String]] = { val dcl = d.symbol.showUser - try { + Try { val resultValue = if (d.symbol.is(Flags.Lazy)) Some("") else valueOf(d.symbol) resultValue.map(value => s"$dcl = $value") } - catch { case ex: InvocationTargetException => Some(renderError(ex)) } + } /** 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 diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 115940d52e5e..1dc5b2391a45 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -1,39 +1,39 @@ package dotty.tools package repl -import java.io.{ InputStream, PrintStream } +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 } +import dotc.{Compiler, Driver} import dotc.printing.SyntaxHighlighting import dotc.reporting.diagnostic.Message import dotc.util.Positions.Position import dotc.util.SourcePosition - import io._ - import AmmoniteReader._ import results._ +import scala.util.Try + /** The state of the REPL contains necessary bindings instead of having to have * mutation * @@ -239,14 +239,15 @@ class ReplDriver(settings: Array[String], // display warnings displayErrors(newState.run.runContext.flushBufferedMessages())(newState) - displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports) + val finalState = displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports) + finalState.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) = { @@ -279,15 +280,27 @@ 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 r2: Seq[Try[Option[String]]] = vals.map(rendering.renderVal2) + val (successes, failures) = r2.partition(_.isSuccess) + if (failures.isEmpty) { + val valRender = successes.map(_.get).flatten + ( + 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 { + failures.foreach(fail => fail.failed.get match { + case (ite: InvocationTargetException) => out.println(SyntaxHighlighting(rendering.renderError(ite))) + case _ => out.println("") + }) + None + } } - else state + else Some(state) def isSyntheticCompanion(sym: Symbol) = sym.is(Module) && sym.is(Synthetic) @@ -313,7 +326,7 @@ class ReplDriver(settings: Array[String], } .getOrElse { // user defined a trait/class/object, so no module needed - state + Some(state) } } } From 0d4d5db272e6c7e5ff2ad82da6910c767a7f3b27 Mon Sep 17 00:00:00 2001 From: Ankit Soni Date: Mon, 30 Apr 2018 12:44:15 -0700 Subject: [PATCH 2/6] cleanup --- compiler/src/dotty/tools/repl/Rendering.scala | 19 +-------------- .../src/dotty/tools/repl/ReplDriver.scala | 23 ++++++++++--------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/compiler/src/dotty/tools/repl/Rendering.scala b/compiler/src/dotty/tools/repl/Rendering.scala index 90c5555f97ed..374e77435552 100644 --- a/compiler/src/dotty/tools/repl/Rendering.scala +++ b/compiler/src/dotty/tools/repl/Rendering.scala @@ -71,24 +71,7 @@ private[repl] class Rendering(compiler: ReplCompiler, d.symbol.showUser /** Render value definition result */ - def renderVal(d: Denotation)(implicit ctx: Context): Either[String,Option[String]] = { - val dcl = d.symbol.showUser - - Try { - val resultValue = - if (d.symbol.is(Flags.Lazy)) Some("") - else valueOf(d.symbol) - - resultValue.map(value => s"$dcl = $value") - } match { - case Success(s) => Right(s) - case Failure(ex: InvocationTargetException) => Left(renderError(ex)) - case Failure(e) => Left("") - } - - } - - def renderVal2(d: Denotation)(implicit ctx: Context): Try[Option[String]] = { + def renderVal(d: Denotation)(implicit ctx: Context): Try[Option[String]] = { val dcl = d.symbol.showUser Try { diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 1dc5b2391a45..aedbd679497c 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -280,23 +280,16 @@ class ReplDriver(settings: Array[String], val typeAliases = info.bounds.hi.typeMembers.filter(_.symbol.info.isInstanceOf[TypeAlias]) - - val r2: Seq[Try[Option[String]]] = vals.map(rendering.renderVal2) - val (successes, failures) = r2.partition(_.isSuccess) + val (successes, failures) = vals.map(rendering.renderVal).partition(_.isSuccess) if (failures.isEmpty) { - val valRender = successes.map(_.get).flatten - ( - typeAliases.map("// defined alias " + _.symbol.showUser) ++ + 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 { - failures.foreach(fail => fail.failed.get match { - case (ite: InvocationTargetException) => out.println(SyntaxHighlighting(rendering.renderError(ite))) - case _ => out.println("") - }) + displayRenderFailures(failures.map(_.failed.get)) None } } @@ -399,4 +392,12 @@ class ReplDriver(settings: Array[String], errs.map(renderMessage(_)(state.run.runContext)).foreach(out.println) state } + + private def displayRenderFailures(failures: Seq[Throwable]) = { + failures.foreach(f => f match { + case (ite: InvocationTargetException) => out.println(SyntaxHighlighting(rendering.renderError(ite))) + case _ => out.println("") + }) + + } } From d1134157b845e4161d9e52b48ac05c31b3c08e2f Mon Sep 17 00:00:00 2001 From: Ankit Soni Date: Mon, 30 Apr 2018 13:35:39 -0700 Subject: [PATCH 3/6] style --- compiler/src/dotty/tools/repl/Rendering.scala | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/repl/Rendering.scala b/compiler/src/dotty/tools/repl/Rendering.scala index 374e77435552..d41c784871f6 100644 --- a/compiler/src/dotty/tools/repl/Rendering.scala +++ b/compiler/src/dotty/tools/repl/Rendering.scala @@ -1,19 +1,16 @@ package dotty.tools package repl -import java.io.{PrintWriter, StringWriter} -import java.lang.{ClassLoader, ExceptionInInitializerError} +import java.io.{ PrintWriter, StringWriter } import java.lang.reflect.InvocationTargetException -import scala.util.control.NonFatal -import dotc.core.Types._ import dotc.core.Contexts.Context import dotc.core.Denotations.Denotation import dotc.core.Flags import dotc.core.Symbols.Symbol import dotc.core.StdNames.str -import scala.util.{Failure, Success, Try} +import scala.util.Try /** This rendering object uses `ClassLoader`s to accomplish crossing the 4th * wall (i.e. fetching back values from the compiled class files put into a From 479396f5a80732c86bb9cc1e015ebd630f4adf37 Mon Sep 17 00:00:00 2001 From: Ankit Soni Date: Tue, 1 May 2018 20:48:44 -0700 Subject: [PATCH 4/6] style fixes --- compiler/src/dotty/tools/repl/Rendering.scala | 5 ++--- compiler/src/dotty/tools/repl/ReplDriver.scala | 14 ++++++-------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/repl/Rendering.scala b/compiler/src/dotty/tools/repl/Rendering.scala index d41c784871f6..95619623f76b 100644 --- a/compiler/src/dotty/tools/repl/Rendering.scala +++ b/compiler/src/dotty/tools/repl/Rendering.scala @@ -4,14 +4,14 @@ package repl import java.io.{ PrintWriter, StringWriter } import java.lang.reflect.InvocationTargetException +import scala.util.Try + import dotc.core.Contexts.Context import dotc.core.Denotations.Denotation import dotc.core.Flags import dotc.core.Symbols.Symbol import dotc.core.StdNames.str -import scala.util.Try - /** This rendering object uses `ClassLoader`s to accomplish crossing the 4th * wall (i.e. fetching back values from the compiled class files put into a * specific class loader capable of loading from memory) and rendering them. @@ -78,7 +78,6 @@ private[repl] class Rendering(compiler: ReplCompiler, resultValue.map(value => s"$dcl = $value") } - } /** Render the stack trace of the underlying exception */ diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index aedbd679497c..636c57f35bd8 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -1,7 +1,7 @@ package dotty.tools package repl -import java.io.{InputStream, PrintStream} +import java.io.{ InputStream, PrintStream } import java.lang.reflect.InvocationTargetException import scala.annotation.tailrec @@ -9,7 +9,7 @@ import dotc.reporting.MessageRendering import dotc.reporting.diagnostic.MessageContainer import dotc.ast.untpd import dotc.ast.tpd -import dotc.interactive.{Interactive, SourceTree} +import dotc.interactive.{ Interactive, SourceTree } import dotc.core.Contexts.Context import dotc.{CompilationUnit, Run} import dotc.core.Mode @@ -20,7 +20,7 @@ import dotc.core.Names.Name import dotc.core.NameOps._ import dotc.core.Symbols.{NoSymbol, Symbol, defn} import dotc.core.Denotations.Denotation -import dotc.core.Types.{ConstantType, ExprType} +import dotc.core.Types.{ ConstantType, ExprType } import dotc.core.NameKinds.SimpleNameKind import dotc.config.CompilerCommand import dotc.{Compiler, Driver} @@ -32,8 +32,6 @@ import io._ import AmmoniteReader._ import results._ -import scala.util.Try - /** The state of the REPL contains necessary bindings instead of having to have * mutation * @@ -239,8 +237,8 @@ class ReplDriver(settings: Array[String], // display warnings displayErrors(newState.run.runContext.flushBufferedMessages())(newState) - val finalState = displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports) - finalState.getOrElse(state) + val afterRender = displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports) + afterRender.getOrElse(state) } } ) @@ -393,7 +391,7 @@ class ReplDriver(settings: Array[String], state } - private def displayRenderFailures(failures: Seq[Throwable]) = { + private def displayRenderFailures(failures: Seq[Throwable]): Unit = { failures.foreach(f => f match { case (ite: InvocationTargetException) => out.println(SyntaxHighlighting(rendering.renderError(ite))) case _ => out.println("") From e145af333041733c1967e14bb4885768bb4aa22f Mon Sep 17 00:00:00 2001 From: Ankit Soni Date: Tue, 1 May 2018 20:51:52 -0700 Subject: [PATCH 5/6] more style fixes --- compiler/src/dotty/tools/repl/ReplDriver.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 636c57f35bd8..4f6b21ec54f8 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -18,17 +18,19 @@ import dotc.core.Types._ import dotc.core.StdNames._ import dotc.core.Names.Name import dotc.core.NameOps._ -import dotc.core.Symbols.{NoSymbol, Symbol, defn} +import dotc.core.Symbols.{ NoSymbol, Symbol, defn } import dotc.core.Denotations.Denotation import dotc.core.Types.{ ConstantType, ExprType } import dotc.core.NameKinds.SimpleNameKind import dotc.config.CompilerCommand -import dotc.{Compiler, Driver} +import dotc.{ Compiler, Driver } import dotc.printing.SyntaxHighlighting import dotc.reporting.diagnostic.Message import dotc.util.Positions.Position import dotc.util.SourcePosition + import io._ + import AmmoniteReader._ import results._ From 6d0228f9eaa19c48f3b3b92d5e50288bb9a411c3 Mon Sep 17 00:00:00 2001 From: Ankit Soni Date: Fri, 19 Oct 2018 10:42:10 -0700 Subject: [PATCH 6/6] Fix #4416 --- compiler/src/dotty/tools/repl/Rendering.scala | 6 +- .../src/dotty/tools/repl/ReplDriver.scala | 63 ++++++++++--------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/compiler/src/dotty/tools/repl/Rendering.scala b/compiler/src/dotty/tools/repl/Rendering.scala index b5cf9089e2d7..6d12549d79ad 100644 --- a/compiler/src/dotty/tools/repl/Rendering.scala +++ b/compiler/src/dotty/tools/repl/Rendering.scala @@ -1,18 +1,20 @@ package dotty.tools package repl -import java.io.{ PrintWriter, StringWriter } +import java.io.{PrintWriter, StringWriter} +import java.lang.{ClassLoader, ExceptionInInitializerError} import java.lang.reflect.InvocationTargetException import scala.util.Try import scala.runtime.ScalaRunTime - import dotc.core.Contexts.Context import dotc.core.Denotations.Denotation import dotc.core.Flags import dotc.core.Symbols.Symbol import dotc.core.StdNames.str +import scala.util.Try + /** This rendering object uses `ClassLoader`s to accomplish crossing the 4th * wall (i.e. fetching back values from the compiled class files put into a * specific class loader capable of loading from memory) and rendering them. diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 7a7084977275..c5531519188e 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -1,6 +1,7 @@ package dotty.tools.repl import java.io.PrintStream +import java.lang.reflect.InvocationTargetException import dotty.tools.dotc.ast.Trees._ import dotty.tools.dotc.ast.{tpd, untpd} @@ -26,6 +27,7 @@ import java.lang.reflect.InvocationTargetException import scala.annotation.tailrec import scala.collection.JavaConverters._ +import scala.util.{Failure, Success} /** The state of the REPL contains necessary bindings instead of having to have * mutation @@ -223,13 +225,11 @@ class ReplDriver(settings: Array[String], allImports += (newState.objectIndex -> newImports) val newStateWithImports = newState.copy(imports = allImports) - // display warnings val warnings = newState.context.reporter.removeBufferedMessages(newState.context) - displayErrors(warnings)(newState) + displayErrors(warnings)(newState) // display warnings - val afterRender = displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports) - afterRender.getOrElse(state) - } + displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports).getOrElse(state) + } ) } @@ -267,17 +267,37 @@ class ReplDriver(settings: Array[String], val typeAliases = info.bounds.hi.typeMembers.filter(_.symbol.info.isTypeAlias) - val (successes, failures) = vals.map(rendering.renderVal).partition(_.isSuccess) - if (failures.isEmpty) { - val valRender = successes.flatMap(_.get) - (typeAliases.map("// defined alias " + _.symbol.showUser) ++ + var renderedVals: List[Option[String]] = Nil + var error: InvocationTargetException = null + import scala.util.control.Breaks.{break, breakable} + breakable { + for (v <- vals) { + val render = rendering.renderVal(v) + render match { + case Success(rv) => + renderedVals = renderedVals :+ rv + case Failure(th) => th match { + case ex: InvocationTargetException => + error = ex + break() + case other => + throw other + } + } + } + } + + if (error != null) { + out.println(SyntaxHighlighting.highlight(rendering.renderError(error))) + rendering = new Rendering(classLoader) + None + } else { + ( + typeAliases.map("// defined alias " + _.symbol.showUser) ++ defs.map(rendering.renderMethod) ++ - valRender + renderedVals.flatten ).foreach(str => out.println(SyntaxHighlighting.highlight(str))) - Some(state.copy(valIndex = state.valIndex - vals.filter(resAndUnit).length)) - } else { - displayRenderFailures(failures.map(_.failed.get)) - None + Some(state.copy(valIndex = state.valIndex - vals.count(resAndUnit))) } } else Some(state) @@ -303,18 +323,13 @@ class ReplDriver(settings: Array[String], ctx.atPhase(ctx.typerPhase.next) { implicit ctx => - // Display members of wrapped module: tree.symbol.info.memberClasses .find(_.symbol.name == newestWrapper.moduleClassName) - .map { wrapperModule => + .flatMap { wrapperModule => displayTypeDefs(wrapperModule.symbol) displayMembers(wrapperModule.symbol) } - .getOrElse { - // user defined a trait/class/object, so no module needed - Some(state) - } } } @@ -383,12 +398,4 @@ class ReplDriver(settings: Array[String], errs.map(renderMessage(_)(state.context)).foreach(out.println) state } - - private def displayRenderFailures(failures: Seq[Throwable])(implicit state: State): Unit = { - failures.foreach(f => f match { - case (ite: InvocationTargetException) => out.println(SyntaxHighlighting.highlight(rendering.renderError(ite))(state.context)) - case _ => out.println("") - }) - - } }