diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2016-02-05 00:34:02 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-02-05 00:34:02 +0100 |
commit | 9d8c92d1d52fcfa95d57ce88d91dbb84c8ecfbd1 (patch) | |
tree | 83b51507c3548d95a02840b83d530e3b6c700e0f | |
parent | 93dd1cf1fdbf56ca3c153aa5a25fb4c48782acf5 (diff) | |
parent | 7eba7f7a6778cc0ddfb2ce81dee64dd4fa23490a (diff) | |
download | dotty-9d8c92d1d52fcfa95d57ce88d91dbb84c8ecfbd1.tar.gz dotty-9d8c92d1d52fcfa95d57ce88d91dbb84c8ecfbd1.tar.bz2 dotty-9d8c92d1d52fcfa95d57ce88d91dbb84c8ecfbd1.zip |
Merge pull request #1052 from smarter/fix/driver-api
Improve and document the Driver#process API, fix partest logging
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/CompilerCallback.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/Driver.scala | 68 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 24 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/ConsoleReporter.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/Reporter.scala | 21 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeChecker.scala | 3 | ||||
-rw-r--r-- | test/dotty/partest/DPDirectCompiler.scala | 18 | ||||
-rw-r--r-- | test/test/CompilerTest.scala | 4 | ||||
-rw-r--r-- | test/test/DottyTest.scala | 11 |
10 files changed, 86 insertions, 71 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 42d223fe9..199657864 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -111,15 +111,13 @@ class Compiler { .setOwner(defn.RootClass) .setTyper(new Typer) .setMode(Mode.ImplicitsEnabled) - .setTyperState(new MutableTyperState(ctx.typerState, rootReporter(ctx), isCommittable = true)) + .setTyperState(new MutableTyperState(ctx.typerState, ctx.typerState.reporter, isCommittable = true)) ctx.definitions.init(start) // set context of definitions to start def addImport(ctx: Context, refFn: () => TermRef) = ctx.fresh.setImportInfo(ImportInfo.rootImport(refFn)(ctx)) (start.setRunInfo(new RunInfo(start)) /: defn.RootImportFns)(addImport) } - protected def rootReporter(implicit ctx: Context): Reporter = new ConsoleReporter()(ctx) - def reset()(implicit ctx: Context): Unit = { ctx.base.reset() ctx.runInfo.clear() diff --git a/src/dotty/tools/dotc/CompilerCallback.scala b/src/dotty/tools/dotc/CompilerCallback.scala index 98e8e2713..e2f56430b 100644 --- a/src/dotty/tools/dotc/CompilerCallback.scala +++ b/src/dotty/tools/dotc/CompilerCallback.scala @@ -18,7 +18,7 @@ import java.io.File * } * dotty.tools.dotc.process(args, callback) * // Or, if you have a custom root context `rootCtx`: - * dotty.tools.dotc.process(args, rootCtx.setCompilerCallback(callback)) + * dotty.tools.dotc.process(args, rootCtx.fresh.setCompilerCallback(callback)) * }}} */ trait CompilerCallback { diff --git a/src/dotty/tools/dotc/Driver.scala b/src/dotty/tools/dotc/Driver.scala index 1627b6e48..7f22fc774 100644 --- a/src/dotty/tools/dotc/Driver.scala +++ b/src/dotty/tools/dotc/Driver.scala @@ -33,28 +33,64 @@ abstract class Driver extends DotClass { protected def sourcesRequired = true def setup(args: Array[String], rootCtx: Context): (List[String], Context) = { - val summary = CompilerCommand.distill(args)(rootCtx) - // FIXME: We should reuse rootCtx instead of creating newCtx, but this - // makes some tests fail with "denotation module _root_ invalid in run 2." - val newCtx = initCtx.setCompilerCallback(rootCtx.compilerCallback) - implicit val ctx: Context = newCtx.fresh.setSettings(summary.sstate) - val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired) + val ctx = rootCtx.fresh + val summary = CompilerCommand.distill(args)(ctx) + ctx.setSettings(summary.sstate) + val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)(ctx) (fileNames, ctx) } - def process(args: Array[String], rootCtx: Context): Reporter = { - val (fileNames, ctx) = setup(args, rootCtx) - doCompile(newCompiler(), fileNames)(ctx) - } - def process(args: Array[String], callback: CompilerCallback): Reporter = { - process(args, initCtx.setCompilerCallback(callback)) + /** Principal entry point to the compiler. + * Creates a new compiler instance and run it with arguments `args`. + * + * The optional arguments of this method all have `null` as their default + * value, this makes it easier to call this method by reflection or from Java. + * + * @param args Arguments to pass to the compiler. + * @param reporter Used to log errors, warnings, and info messages. + * The default reporter is used if this is `null`. + * @param callback Used to execute custom code during the compilation + * process. No callbacks will be executed if this is `null`. + * @return The `Reporter` used. Use `Reporter#hasErrors` to check + * if compilation succeeded. + */ + final def process(args: Array[String], reporter: Reporter = null, + callback: CompilerCallback = null): Reporter = { + val ctx = initCtx.fresh + if (reporter != null) + ctx.setReporter(reporter) + if (callback != null) + ctx.setCompilerCallback(callback) + process(args, ctx) } - // We overload `process` instead of using a default argument so that we - // can easily call this method using reflection from `RawCompiler` in sbt. - def process(args: Array[String]): Reporter = { - process(args, initCtx) + /** Entry point to the compiler with no optional arguments. + * + * This overload is provided for compatibility reasons: the + * `RawCompiler` of sbt expects this method to exist and calls + * it using reflection. Keeping it means that we can change + * the other overloads without worrying about breaking compatibility + * with sbt. + */ + final def process(args: Array[String]): Reporter = + process(args, null, null) + + /** Entry point to the compiler using a custom `Context`. + * + * In most cases, you do not need a custom `Context` and should + * instead use one of the other overloads of `process`. However, + * the other overloads cannot be overriden, instead you + * should override this one which they call internally. + * + * @param args Arguments to pass to the compiler. + * @param rootCtx The root Context to use. + * @return The `Reporter` used. Use `Reporter#hasErrors` to check + * if compilation succeeded. + */ + def process(args: Array[String], rootCtx: Context): Reporter = { + val (fileNames, ctx) = setup(args, rootCtx) + doCompile(newCompiler(), fileNames)(ctx) } def main(args: Array[String]): Unit = { diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index ae221cc3e..b205a40f0 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -72,22 +72,16 @@ object Contexts { def next = { val c = current; current = current.outer; c } } - /** Set the compiler callback, shared by all contexts with the same `base` */ - def setCompilerCallback(callback: CompilerCallback): this.type = { - base.compilerCallback = callback; this - } - /** The outer context */ private[this] var _outer: Context = _ protected def outer_=(outer: Context) = _outer = outer def outer: Context = _outer - // protected def compilerCallback_=(callback: CompilerCallback) = - // _compilerCallback = callback - // def compilerCallback: CompilerCallback = _compilerCallback - // def setCompilerCallback(callback: CompilerCallback): this.type = { - // this.compilerCallback = callback; this - // } + /** The compiler callback implementation, or null if no callback will be called. */ + private[this] var _compilerCallback: CompilerCallback = _ + protected def compilerCallback_=(callback: CompilerCallback) = + _compilerCallback = callback + def compilerCallback: CompilerCallback = _compilerCallback /** The current context */ private[this] var _period: Period = _ @@ -426,7 +420,9 @@ object Contexts { abstract class FreshContext extends Context { def setPeriod(period: Period): this.type = { this.period = period; this } def setMode(mode: Mode): this.type = { this.mode = mode; this } + def setCompilerCallback(callback: CompilerCallback): this.type = { this.compilerCallback = callback; this } def setTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this } + def setReporter(reporter: Reporter): this.type = setTyperState(typerState.withReporter(reporter)) def setNewTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true)) def setExploreTyperState: this.type = setTyperState(typerState.fresh(isCommittable = false)) def setPrinterFn(printer: Context => Printer): this.type = { this.printerFn = printer; this } @@ -481,7 +477,7 @@ object Contexts { outer = NoContext period = InitialPeriod mode = Mode.None - typerState = new TyperState(new ThrowingReporter(new ConsoleReporter()(this))) + typerState = new TyperState(new ConsoleReporter()) printerFn = new RefinedPrinter(_) owner = NoSymbol sstate = settings.defaultState @@ -536,10 +532,6 @@ object Contexts { /** The essential mutable state of a context base, collected into a common class */ class ContextState { - - /** The compiler callback implementation, or null if unset */ - var compilerCallback: CompilerCallback = _ - // Symbols state /** A counter for unique ids */ diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 45268b673..e9b9964c3 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -15,7 +15,7 @@ import scala.reflect.internal.util._ */ class ConsoleReporter( reader: BufferedReader = Console.in, - writer: PrintWriter = new PrintWriter(Console.err, true))(ctx: Context) + writer: PrintWriter = new PrintWriter(Console.err, true)) extends Reporter with UniqueMessagePositions { /** maximal number of error messages to be printed */ diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala index f98d85ce9..5ed7360da 100644 --- a/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -247,12 +247,23 @@ abstract class Reporter { incompleteHandler(d)(ctx) - /** Print a summary */ - def printSummary(implicit ctx: Context): Unit = { - if (warningCount > 0) ctx.println(countString(warningCount, "warning") + " found") - if (errorCount > 0) ctx.println(countString(errorCount, "error") + " found") + /** Summary of warnings and errors */ + def summary: String = { + val b = new mutable.ListBuffer[String] + if (warningCount > 0) + b += countString(warningCount, "warning") + " found" + if (errorCount > 0) + b += countString(errorCount, "error") + " found" for ((settingName, count) <- unreportedWarnings) - ctx.println(s"there were $count ${settingName.tail} warning(s); re-run with $settingName for details") + b += s"there were $count ${settingName.tail} warning(s); re-run with $settingName for details" + b.mkString("\n") + } + + /** Print the summary of warnings and errors */ + def printSummary(implicit ctx: Context): Unit = { + val s = summary + if (s != "") + ctx.println(s) } /** Returns a string meaning "n elements". */ diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index daf76f471..150a632a1 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -118,8 +118,7 @@ class TreeChecker extends Phase with SymTransformer { val prevPhase = ctx.phase.prev // can be a mini-phase val squahsedPhase = ctx.squashed(prevPhase) ctx.println(s"checking ${ctx.compilationUnit} after phase ${squahsedPhase}") - val checkingCtx = ctx.fresh - .setTyperState(ctx.typerState.withReporter(new ThrowingReporter(ctx.reporter))) + val checkingCtx = ctx.fresh.setReporter(new ThrowingReporter(ctx.reporter)) val checker = new Checker(previousPhases(phasesToRun.toList)(ctx)) try checker.typedExpr(ctx.compilationUnit.tpdTree)(checkingCtx) catch { diff --git a/test/dotty/partest/DPDirectCompiler.scala b/test/dotty/partest/DPDirectCompiler.scala index ca56ac3e9..410dac338 100644 --- a/test/dotty/partest/DPDirectCompiler.scala +++ b/test/dotty/partest/DPDirectCompiler.scala @@ -5,7 +5,7 @@ import scala.tools.partest.{ TestState, nest } import java.io.{ File, PrintWriter, FileWriter } -/* NOTE: Adapted from partest.DirectCompiler and DottyTest */ +/* NOTE: Adapted from partest.DirectCompiler */ class DPDirectCompiler(runner: DPTestRunner) extends nest.DirectCompiler(runner) { override def compile(opts0: List[String], sources: List[File]): TestState = { @@ -13,24 +13,14 @@ class DPDirectCompiler(runner: DPTestRunner) extends nest.DirectCompiler(runner) val clogWriter = new PrintWriter(clogFWriter, true) clogWriter.println("\ncompiling " + sources.mkString(" ") + "\noptions: " + opts0.mkString(" ")) - implicit val ctx: dotty.tools.dotc.core.Contexts.Context = { - val base = new dotty.tools.dotc.core.Contexts.ContextBase - import base.settings._ - val ctx = base.initialCtx.fresh.setSetting(printtypes, true) - .setSetting(pageWidth, 90).setSetting(log, List("<some")) - base.definitions.init(ctx) - ctx - } - try { val processor = if (opts0.exists(_.startsWith("#"))) dotty.tools.dotc.Bench else dotty.tools.dotc.Main - val clogger = new ConsoleReporter(writer = clogWriter)(ctx) - val logCtx = ctx.fresh.setTyperState(ctx.typerState.withReporter(clogger)) - val reporter = processor.process((sources.map(_.toString) ::: opts0).toArray, logCtx) + val clogger = new ConsoleReporter(writer = clogWriter) + val reporter = processor.process((sources.map(_.toString) ::: opts0).toArray, clogger) if (!reporter.hasErrors) runner.genPass() else { - reporter.printSummary(ctx) + clogWriter.println(reporter.summary) runner.genFail(s"compilation failed with ${reporter.errorCount} errors") } } catch { diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala index c65710e7d..526392576 100644 --- a/test/test/CompilerTest.scala +++ b/test/test/CompilerTest.scala @@ -33,7 +33,7 @@ import org.junit.Test * object Test { def main(args: Array[String]): Unit = ... } * Classpath jars can be added to partestDeps in the sbt Build.scala. */ -abstract class CompilerTest extends DottyTest { +abstract class CompilerTest { /** Override with output dir of test so it can be patched. Partest expects * classes to be in partest-generated/[kind]/[testname]-[kind].obj/ */ @@ -181,7 +181,7 @@ abstract class CompilerTest extends DottyTest { private def compileArgs(args: Array[String], xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = { val allArgs = args ++ defaultOptions val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main - val nerrors = processor.process(allArgs, ctx).errorCount + val nerrors = processor.process(allArgs).errorCount assert(nerrors == xerrors, s"Wrong # of errors. Expected: $xerrors, found: $nerrors") } diff --git a/test/test/DottyTest.scala b/test/test/DottyTest.scala index fc9cff782..4664605d1 100644 --- a/test/test/DottyTest.scala +++ b/test/test/DottyTest.scala @@ -22,17 +22,6 @@ class DottyTest /*extends ContextEscapeDetection*/ { val base = new ContextBase import base.settings._ val ctx = base.initialCtx.fresh - //.setSetting(verbose, true) - // .withSetting(debug, true) - // .withSetting(debugTrace, true) - // .withSetting(prompt, true) - //.setSetting(Ylogcp, true) - //.setSetting(printtypes, true) - .setSetting(pageWidth, 90) - .setSetting(log, List("<some")) - // .withTyperState(new TyperState(new ConsoleReporter()(base.initialCtx))) - - // .withSetting(uniqid, true) base.definitions.init(ctx) ctx } |