diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-06-10 16:24:37 +0200 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-07-04 15:49:05 +0200 |
commit | 98216be3f3e546fc320ab5182ac5c129707db1ce (patch) | |
tree | 1c20acf20ecfdfa37dd49ed53d82039af58c9e29 /src/compiler/scala/tools/nsc/Global.scala | |
parent | f2b76e80094219db1f72a7a56d02f21bab1fc9eb (diff) | |
download | scala-98216be3f3e546fc320ab5182ac5c129707db1ce.tar.gz scala-98216be3f3e546fc320ab5182ac5c129707db1ce.tar.bz2 scala-98216be3f3e546fc320ab5182ac5c129707db1ce.zip |
Move reporting logic into Reporting trait
Move code from Global/SymbolTable to separate Reporting traits to
start carving out an interface in scala.reflect.internal.Reporting,
with internals in scala.tools.nsc. Reporting is mixed into the cake.
It contains a nested class PerRunReporting.
Should do the same for debugging/logging.
The idea is that CompilationUnit and Global forward all reporting
to Reporter. The Reporting trait contains these forwarders, and
PerRunReporting, which accumulates warning state during a run.
In the process, I slightly changed the behavior of `globalError`
in reflect.internal.SymbolTable: it used to abort, weirdly.
I assume that was dummy behavior to avoid introducing an abstract method.
It's immediately overridden in Global, and I couldn't find any other subclasses,
so I don't think the behavior in SymbolTable was ever observed.
Provide necessary hooks for scala.reflect.macros.Parsers#parse.
See scala/reflect/macros/contexts/Parsers.scala's parse method,
which overrides the reporter to detect when parsing goes wrong.
This should be refactored, but that goes beyond the scope of this PR.
Don't pop empty macro context stack.
(Ran into this while reworking -Xfatal-warnings logic.)
Fix -Xfatal-warnings behavior (and check files): it wasn't meant to
influence warning reporting, except for emitting one final error;
if necessary to fail the compile (when warnings but no errors were reported).
Warnings should stay warnings.
This was refactored in fbbbb22946, but we soon seem to have relapsed.
An hour of gitfu did not lead to where it went wrong. Must've been a merge.
Diffstat (limited to 'src/compiler/scala/tools/nsc/Global.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 150 |
1 files changed, 45 insertions, 105 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 836203e80d..daf69ffc3f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -44,7 +44,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) with Trees with Printers with DocComments - with Positions { self => + with Positions + with Reporting { self => // the mirror -------------------------------------------------- @@ -227,20 +228,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) */ def registerTopLevelSym(sym: Symbol) {} -// ------------------ Reporting ------------------------------------- - - // not deprecated yet, but a method called "error" imported into - // nearly every trait really must go. For now using globalError. - def error(msg: String) = globalError(msg) - - override def inform(msg: String) = inform(NoPosition, msg) - override def globalError(msg: String) = globalError(NoPosition, msg) - override def warning(msg: String) = warning(NoPosition, msg) - override def deprecationWarning(pos: Position, msg: String) = currentUnit.deprecationWarning(pos, msg) - - def globalError(pos: Position, msg: String) = reporter.error(pos, msg) - def warning(pos: Position, msg: String) = if (settings.fatalWarnings) globalError(pos, msg) else reporter.warning(pos, msg) - def inform(pos: Position, msg: String) = reporter.echo(pos, msg) +// ------------------ Debugging ------------------------------------- // Getting in front of Predef's asserts to supplement with more info. // This has the happy side effect of masking the one argument forms @@ -263,12 +251,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) require(requirement, "") } - // Needs to call error to make sure the compile fails. - override def abort(msg: String): Nothing = { - error(msg) - super.abort(msg) - } - @inline final def ifDebug(body: => Unit) { if (settings.debug) body @@ -1063,6 +1045,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile def currentFreshNameCreator = currentUnit.fresh + def currentReporting = currentRun.reporting def isGlobalInitialized = ( definitions.isDefinitionsInitialized @@ -1110,45 +1093,41 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Don't want to introduce new errors trying to report errors, * so swallow exceptions. */ - override def supplementErrorMessage(errorMessage: String): String = { - if (currentRun.supplementedError) errorMessage - else try { - currentRun.supplementedError = true - val tree = analyzer.lastTreeToTyper - val sym = tree.symbol - val tpe = tree.tpe - val site = lastSeenContext.enclClassOrMethod.owner - val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "<unknown>" - val context_s = try { - // Taking 3 before, 3 after the fingered line. - val start = 0 max (tree.pos.line - 3) - val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7 - val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" } - strs.mkString("== Source file context for tree position ==\n\n", "\n", "") - } - catch { case t: Exception => devWarning("" + t) ; "<Cannot read source file>" } - - val info1 = formatExplain( - "while compiling" -> currentSource.path, - "during phase" -> ( if (globalPhase eq phase) phase else "globalPhase=%s, enteringPhase=%s".format(globalPhase, phase) ), - "library version" -> scala.util.Properties.versionString, - "compiler version" -> Properties.versionString, - "reconstructed args" -> settings.recreateArgs.mkString(" ") - ) - val info2 = formatExplain( - "last tree to typer" -> tree.summaryString, - "tree position" -> pos_s, - "tree tpe" -> tpe, - "symbol" -> Option(sym).fold("null")(_.debugLocationString), - "symbol definition" -> Option(sym).fold("null")(s => s.defString + s" (a ${s.shortSymbolClass})"), - "symbol package" -> sym.enclosingPackage.fullName, - "symbol owners" -> ownerChainString(sym), - "call site" -> (site.fullLocationString + " in " + site.enclosingPackage) - ) - ("\n " + errorMessage + "\n" + info1) :: info2 :: context_s :: Nil mkString "\n\n" + def supplementTyperState(errorMessage: String): String = try { + val tree = analyzer.lastTreeToTyper + val sym = tree.symbol + val tpe = tree.tpe + val site = lastSeenContext.enclClassOrMethod.owner + val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "<unknown>" + val context_s = try { + // Taking 3 before, 3 after the fingered line. + val start = 0 max (tree.pos.line - 3) + val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7 + val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" } + strs.mkString("== Source file context for tree position ==\n\n", "\n", "") } - catch { case _: Exception | _: TypeError => errorMessage } - } + catch { case t: Exception => devWarning("" + t) ; "<Cannot read source file>" } + + val info1 = formatExplain( + "while compiling" -> currentSource.path, + "during phase" -> ( if (globalPhase eq phase) phase else "globalPhase=%s, enteringPhase=%s".format(globalPhase, phase) ), + "library version" -> scala.util.Properties.versionString, + "compiler version" -> Properties.versionString, + "reconstructed args" -> settings.recreateArgs.mkString(" ") + ) + val info2 = formatExplain( + "last tree to typer" -> tree.summaryString, + "tree position" -> pos_s, + "tree tpe" -> tpe, + "symbol" -> Option(sym).fold("null")(_.debugLocationString), + "symbol definition" -> Option(sym).fold("null")(s => s.defString + s" (a ${s.shortSymbolClass})"), + "symbol package" -> sym.enclosingPackage.fullName, + "symbol owners" -> ownerChainString(sym), + "call site" -> (site.fullLocationString + " in " + site.enclosingPackage) + ) + ("\n " + errorMessage + "\n" + info1) :: info2 :: context_s :: Nil mkString "\n\n" + } catch { case _: Exception | _: TypeError => errorMessage } + /** The id of the currently active run */ @@ -1160,19 +1139,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) inform("[running phase " + ph.name + " on " + currentRun.size + " compilation units]") } - /** Collects for certain classes of warnings during this run. */ - class ConditionalWarning(what: String, option: Settings#BooleanSetting) { - val warnings = mutable.LinkedHashMap[Position, String]() - def warn(pos: Position, msg: String) = - if (option) reporter.warning(pos, msg) - else if (!(warnings contains pos)) warnings += ((pos, msg)) - def summarize() = - if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)){ - val warningEvent = if (warnings.size > 1) s"were ${ warnings.size } $what warnings" else s"was one $what warning" - warning(s"there $warningEvent; re-run with ${ option.name } for details") - } - } - def newSourceFile(code: String, filename: String = "<console>") = new BatchSourceFile(filename, code) @@ -1199,38 +1165,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** The currently compiled unit; set from GlobalPhase */ var currentUnit: CompilationUnit = NoCompilationUnit - // This change broke sbt; I gave it the thrilling name of uncheckedWarnings0 so - // as to recover uncheckedWarnings for its ever-fragile compiler interface. - val deprecationWarnings0 = new ConditionalWarning("deprecation", settings.deprecation) - val uncheckedWarnings0 = new ConditionalWarning("unchecked", settings.unchecked) - val featureWarnings = new ConditionalWarning("feature", settings.feature) - val inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings) - val allConditionalWarnings = List(deprecationWarnings0, uncheckedWarnings0, featureWarnings, inlinerWarnings) - - def uncheckedWarnings: List[(Position, String)] = uncheckedWarnings0.warnings.toList // used in sbt - def deprecationWarnings: List[(Position, String)] = deprecationWarnings0.warnings.toList // used in sbt - - def reportAdditionalErrors(): Unit = { - if (!reporter.hasErrors) { - if (reporter.hasWarnings && settings.fatalWarnings) - globalError("No warnings can be incurred under -Xfatal-warnings.") - - allConditionalWarnings foreach (_.summarize()) - - if (seenMacroExpansionsFallingBack) - warning("some macros could not be expanded and code fell back to overridden methods;"+ - "\nrecompiling with generated classfiles on the classpath might help.") - // todo: migrationWarnings - } - } - - var reportedFeature = Set[Symbol]() - - /** Has any macro expansion used a fallback during this run? */ - var seenMacroExpansionsFallingBack = false + val reporting = new PerRunReporting - /** Have we already supplemented the error message of a compiler crash? */ - private[nsc] final var supplementedError = false + // used in sbt + def uncheckedWarnings: List[(Position, String)] = reporting.uncheckedWarnings + // used in sbt + def deprecationWarnings: List[(Position, String)] = reporting.deprecationWarnings private class SyncedCompilationBuffer { self => private val underlying = new mutable.ArrayBuffer[CompilationUnit] @@ -1590,7 +1530,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def checkDeprecations() = { checkDeprecatedSettings(newCompilationUnit("")) - reportAdditionalErrors() + reporting.summarizeErrors() } val units = sources map scripted map (new CompilationUnit(_)) @@ -1660,7 +1600,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) advancePhase() } - reportAdditionalErrors() + reporting.summarizeErrors() if (traceSymbolActivity) units map (_.body) foreach (traceSymbols recordSymbolsInTree _) |