From 508ee772ff211d290e0fadc81d8cea70595b7984 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 25 Jul 2013 15:20:28 -0700 Subject: SI-7622 Phase assembly is testable Fixing hash on nodes makes fault detection deterministic, which aids testing. Error messages are shortened and .dot files are dumped automatically on faults to guard against future flakiness. --- test/files/neg/t7494-multi-right-after.check | 4 +--- test/files/neg/t7494-right-after-before.check | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/files/neg/t7494-multi-right-after.check b/test/files/neg/t7494-multi-right-after.check index 9c6fdbe91f..c0e0334aaf 100644 --- a/test/files/neg/t7494-multi-right-after.check +++ b/test/files/neg/t7494-multi-right-after.check @@ -1,3 +1 @@ -error: Multiple phases want to run right after the phase explicitouter -Phases: erasure, multi-rafter, -Re-run with -Xgenerate-phase-graph to better see the problem. +error: Phase explicitouter has too many followers: erasure,multi-rafter; created phase-order.dot diff --git a/test/files/neg/t7494-right-after-before.check b/test/files/neg/t7494-right-after-before.check index 9b57a7711b..7e83daab4a 100644 --- a/test/files/neg/t7494-right-after-before.check +++ b/test/files/neg/t7494-right-after-before.check @@ -1 +1 @@ -error: phase erasure want to run right after explicitouter, but some phase has declared to run before erasure. Re-run with -Xgenerate-phase-graph to better see the problem. +error: Phase erasure can't follow explicitouter, created phase-order.dot -- cgit v1.2.3 From 591221017b20913bfafde55f7ff8672730bdac82 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 25 Jul 2013 17:35:36 -0700 Subject: SI-7622 Phases are enabled or not Refactor the calculation of the "phase chain" a bit. In particular, initial and terminal phases are not special except that they must be head and last. When done, filter for enabled phases. At this commit, nobody claims to be disabled. Additional sanity support of phases settings. --- src/compiler/scala/tools/nsc/Global.scala | 165 ++++++++++++++--------- src/compiler/scala/tools/nsc/PhaseAssembly.scala | 2 +- src/compiler/scala/tools/nsc/SubComponent.scala | 21 ++- src/reflect/scala/reflect/internal/Phase.scala | 9 +- test/files/neg/t6446-additional.check | 2 +- test/files/neg/t6446-missing.check | 2 +- test/files/neg/t6446-show-phases.check | 2 +- test/files/neg/t7494-no-options.check | 2 +- test/files/run/programmatic-main.check | 2 +- 9 files changed, 133 insertions(+), 74 deletions(-) (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 3f2d759a6d..a0a9a2fdb7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -47,7 +47,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // the mirror -------------------------------------------------- override def isCompilerUniverse = true - override val useOffsetPositions = !currentSettings.Yrangepos.value + override val useOffsetPositions = !currentSettings.Yrangepos class GlobalMirror extends Roots(NoSymbol) { val universe: self.type = self @@ -430,9 +430,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // phaseName = "parser" lazy val syntaxAnalyzer = new { val global: Global.this.type = Global.this + } with SyntaxAnalyzer { val runsAfter = List[String]() val runsRightAfter = None - } with SyntaxAnalyzer + override val initial = true + } import syntaxAnalyzer.{ UnitScanner, UnitParser } @@ -452,9 +454,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) object patmat extends { val global: Global.this.type = Global.this val runsAfter = List("typer") - // patmat doesn't need to be right after typer, as long as we run before supperaccesors - // (sbt does need to run right after typer, so don't conflict) val runsRightAfter = None + // patmat doesn't need to be right after typer, as long as we run before superaccessors + // (sbt does need to run right after typer, so don't conflict) } with PatternMatching // phaseName = "superaccessors" @@ -628,18 +630,17 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // phaseName = "terminal" object terminal extends { val global: Global.this.type = Global.this - val phaseName = "terminal" + } with SubComponent { + final val phaseName = "terminal" val runsAfter = List("jvm") val runsRightAfter = None - } with SubComponent { - private var cache: Option[GlobalPhase] = None - def reset(): Unit = cache = None + override val terminal = true - def newPhase(prev: Phase): GlobalPhase = - cache getOrElse returning(new TerminalPhase(prev))(x => cache = Some(x)) - - class TerminalPhase(prev: Phase) extends GlobalPhase(prev) { - def name = "terminal" + def newPhase(prev: Phase): GlobalPhase = { + new TerminalPhase(prev) + } + private class TerminalPhase(prev: Phase) extends GlobalPhase(prev) { + def name = phaseName def apply(unit: CompilationUnit) {} } } @@ -667,7 +668,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Add the internal compiler phases to the phases set. * This implementation creates a description map at the same time. */ - protected def computeInternalPhases() { + protected def computeInternalPhases(): Unit = { // Note: this fits -Xshow-phases into 80 column width, which it is // desirable to preserve. val phs = List( @@ -697,7 +698,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) closureElimination -> "optimization: eliminate uncalled closures", constantOptimization -> "optimization: optimize null and other constants", deadCode -> "optimization: eliminate dead code", - terminal -> "The last phase in the compiler chain" + terminal -> "the last phase during a compilation run" ) phs foreach (addToPhasesSet _).tupled @@ -715,13 +716,21 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // sequences the phase assembly protected def computePhaseDescriptors: List[SubComponent] = { - computeInternalPhases() // Global.scala - computePlatformPhases() // backend/Platform.scala - computePluginPhases() // plugins/Plugins.scala - buildCompilerFromPhasesSet() // PhaseAssembly.scala + /** Allow phases to opt out of the phase assembly. */ + def cullPhases(phases: List[SubComponent]) = { + val enabled = if (settings.debug && settings.isInfo) phases else phases filter (_.enabled) + def isEnabled(q: String) = enabled exists (_.phaseName == q) + val (satisfied, unhappy) = enabled partition (_.requires forall isEnabled) + unhappy foreach (u => globalError(s"Phase '${u.phaseName}' requires: ${u.requires filterNot isEnabled}")) + satisfied // they're happy now, but they may need an unhappy phase that was booted + } + computeInternalPhases() // Global.scala + computePlatformPhases() // backend/Platform.scala + computePluginPhases() // plugins/Plugins.scala + cullPhases(computePhaseAssembly()) // PhaseAssembly.scala } - /* The phase descriptor list */ + /* The phase descriptor list. Components that are phase factories. */ lazy val phaseDescriptors: List[SubComponent] = computePhaseDescriptors /* The set of phase objects that is the basis for the compiler phase chain */ @@ -1147,7 +1156,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def newUnitParser(unit: CompilationUnit): UnitParser = new UnitParser(unit) def newUnitParser(code: String): UnitParser = newUnitParser(newCompilationUnit(code)) - /** A Run is a single execution of the compiler on a sets of units + /** A Run is a single execution of the compiler on a set of units. */ class Run extends RunContextApi { /** Have been running into too many init order issues with Run @@ -1186,64 +1195,100 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** A map from compiled top-level symbols to their picklers */ val symData = new mutable.HashMap[Symbol, PickleBuffer] - private var phasec: Int = 0 // phases completed - private var unitc: Int = 0 // units completed this phase + private var phasec: Int = 0 // phases completed + private var unitc: Int = 0 // units completed this phase private var _unitbufSize = 0 def size = _unitbufSize override def toString = "scalac Run for:\n " + compiledFiles.toList.sorted.mkString("\n ") // Calculate where to stop based on settings -Ystop-before or -Ystop-after. - // Slightly complicated logic due to wanting -Ystop-before:parser to fail rather - // than mysteriously running to completion. + // The result is the phase to stop at BEFORE running it. private lazy val stopPhaseSetting = { - val result = phaseDescriptors sliding 2 collectFirst { - case xs if xs exists (settings.stopBefore contains _.phaseName) => if (settings.stopBefore contains xs.head.phaseName) xs.head else xs.last - case xs if settings.stopAfter contains xs.head.phaseName => xs.last + def isBefore(pd: SubComponent) = settings.stopBefore contains pd.phaseName + phaseDescriptors sliding 2 collectFirst { + case xs if xs exists isBefore + => (xs find isBefore).get + case xs if settings.stopAfter contains xs.head.phaseName + => xs.last } - if (result exists (_.phaseName == "parser")) - globalError("Cannot stop before parser phase.") - - result } - // The phase to stop BEFORE running. + /** Should we stop right before entering the given phase? */ protected def stopPhase(name: String) = stopPhaseSetting exists (_.phaseName == name) + /** Should we skip the given phase? */ protected def skipPhase(name: String) = settings.skip contains name - /** As definitions.init requires phase != NoPhase, and calling phaseDescriptors.head - * will force init, there is some jockeying herein regarding init order: instead of - * taking the head descriptor we create a parser phase directly. - */ private val firstPhase = { - /** Initialization. */ + // Initialization. definitions.init requires phase != NoPhase + import scala.reflect.internal.SomePhase curRunId += 1 curRun = this - - /* Set phase to a newly created syntaxAnalyzer and call definitions.init. */ - val parserPhase: Phase = syntaxAnalyzer.newPhase(NoPhase) - phase = parserPhase + phase = SomePhase + phaseWithId(phase.id) = phase definitions.init() - // Flush the cache in the terminal phase: the chain could have been built - // before without being used. (This happens in the interpreter.) - terminal.reset() - - // Each subcomponent supplies a phase, which are chained together. - // If -Ystop:phase is given, neither that phase nor any beyond it is added. - // If -Yskip:phase is given, that phase will be skipped. - val phaseLinks = { - val phs = ( - phaseDescriptors.tail - takeWhile (pd => !stopPhase(pd.phaseName)) - filterNot (pd => skipPhase(pd.phaseName)) - ) + // the components to use, omitting those named by -Yskip and stopping at the -Ystop phase + val components = { + // stop on a dime, but this test fails if pd is after the stop phase + def unstoppable(pd: SubComponent) = { + val stoppable = stopPhase(pd.phaseName) + if (stoppable && pd.initial) { + globalError(s"Cannot stop before initial phase '${pd.phaseName}'.") + true + } else + !stoppable + } + // skip a component for -Yskip or if not enabled + def skippable(pd: SubComponent) = { + val skippable = skipPhase(pd.phaseName) + if (skippable && (pd.initial || pd.terminal)) { + globalError(s"Cannot skip an initial or terminal phase '${pd.phaseName}'.") + false + } else + skippable || !pd.enabled + } + val phs = phaseDescriptors takeWhile unstoppable filterNot skippable // Ensure there is a terminal phase at the end, since -Ystop may have limited the phases. - if (phs.isEmpty || (phs.last ne terminal)) phs :+ terminal - else phs + if (phs.isEmpty || !phs.last.terminal) { + val t = if (phaseDescriptors.last.terminal) phaseDescriptors.last else terminal + phs :+ t + } else phs } - // Link them together. - phaseLinks.foldLeft(parserPhase)((chain, ph) => ph newPhase chain) - parserPhase + // Create phases and link them together. We supply the previous, and the ctor sets prev.next. + val last = components.foldLeft(NoPhase: Phase)((prev, c) => c newPhase prev) + // rewind (Iterator.iterate(last)(_.prev) dropWhile (_.prev ne NoPhase)).next + val first = { var p = last ; while (p.prev ne NoPhase) p = p.prev ; p } + val ss = settings + + // As a final courtesy, see if the settings make any sense at all. + // If a setting selects no phase, it's a mistake. If a name prefix + // doesn't select a unique phase, that might be surprising too. + def checkPhaseSettings(including: Boolean, specs: Seq[String]*) = { + def isRange(s: String) = s.forall(c => c.isDigit || c == '-') + def isSpecial(s: String) = (s == "all" || isRange(s)) + val setting = new ss.PhasesSetting("fake","fake") + for (p <- specs.flatten.to[Set]) { + setting.value = List(p) + val count = ( + if (including) first.iterator count (setting containsPhase _) + else phaseDescriptors count (setting contains _.phaseName) + ) + if (count == 0) warning(s"'$p' specifies no phase") + if (count > 1 && !isSpecial(p)) warning(s"'$p' selects $count phases") + if (!including && isSpecial(p)) globalError(s"-Yskip and -Ystop values must name phases: '$p'") + setting.clear() + } + } + // phases that are excluded; for historical reasons, these settings only select by phase name + val exclusions = List(ss.stopBefore, ss.stopAfter, ss.skip) + val inclusions = ss.visibleSettings collect { + case s: ss.PhasesSetting if !(exclusions contains s) => s.value + } + checkPhaseSettings(including = true, inclusions.toSeq: _*) + checkPhaseSettings(including = false, exclusions map (_.value): _*) + + phase = first //parserPhase + first } /** Reset all classes contained in current project, as determined by diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index c962cc8bb7..45502a19d6 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -194,7 +194,7 @@ trait PhaseAssembly { /** Called by Global#computePhaseDescriptors to compute phase order. */ - def buildCompilerFromPhasesSet(): List[SubComponent] = { + def computePhaseAssembly(): List[SubComponent] = { // Add all phases in the set to the graph val graph = phasesSetToDepGraph(phasesSet) diff --git a/src/compiler/scala/tools/nsc/SubComponent.scala b/src/compiler/scala/tools/nsc/SubComponent.scala index 9b8582ae02..b21d156145 100644 --- a/src/compiler/scala/tools/nsc/SubComponent.scala +++ b/src/compiler/scala/tools/nsc/SubComponent.scala @@ -19,19 +19,30 @@ abstract class SubComponent { /** The name of the phase */ val phaseName: String - /** List of phase names, this phase should run after */ + /** Names of phases that must run before this phase. */ val runsAfter: List[String] - /** List of phase names, this phase should run before */ + /** Names of phases that must run after this phase. Default is `Nil`. */ val runsBefore: List[String] = Nil - /** Phase name this phase will attach itself to, not allowing any phase to come between it - * and the phase name declared */ + /** Name of the phase that this phase must follow immediately. */ val runsRightAfter: Option[String] - /** Internal flag to tell external from internal phases */ + /** Names of phases required by this component. Default is `Nil`. */ + val requires: List[String] = Nil + + /** Is this component enabled? Default is true. */ + def enabled: Boolean = true + + /** True if this phase is not provided by a plug-in. */ val internal: Boolean = true + /** True if this phase runs before all other phases. Usually, `parser`. */ + val initial: Boolean = false + + /** True if this phase runs after all other phases. Usually, `terminal`. */ + val terminal: Boolean = false + /** SubComponent are added to a HashSet and two phases are the same if they have the same name */ override def hashCode() = phaseName.hashCode() diff --git a/src/reflect/scala/reflect/internal/Phase.scala b/src/reflect/scala/reflect/internal/Phase.scala index 450c90ed56..1ecc202a07 100644 --- a/src/reflect/scala/reflect/internal/Phase.scala +++ b/src/reflect/scala/reflect/internal/Phase.scala @@ -26,11 +26,14 @@ abstract class Phase(val prev: Phase) { ) def flagMask: Long = fmask - private var nx: Phase = this + private var nx: Phase = NoPhase - def next: Phase = nx + // does anyone rely on next == this for terminus? + def next: Phase = if (nx eq NoPhase) this else nx def hasNext = next != this - def iterator = Iterator.iterate(this)(_.next) takeWhile (p => p.next != p) + // this definition excludes the terminal phase + //def iterator = Iterator.iterate(this)(_.nx) takeWhile (p => p.next != p) + def iterator = Iterator.iterate(this)(_.nx) takeWhile (_ ne NoPhase) def name: String def description: String = name diff --git a/test/files/neg/t6446-additional.check b/test/files/neg/t6446-additional.check index 24201c07c2..be928095d3 100755 --- a/test/files/neg/t6446-additional.check +++ b/test/files/neg/t6446-additional.check @@ -29,4 +29,4 @@ inlinehandlers 24 optimization: inline exception handlers dce 27 optimization: eliminate dead code jvm 28 generate JVM bytecode ploogin 29 A sample phase that does so many things it's kind of hard... - terminal 30 The last phase in the compiler chain + terminal 30 the last phase during a compilation run diff --git a/test/files/neg/t6446-missing.check b/test/files/neg/t6446-missing.check index 6e5bdcf07c..8ede1bd260 100755 --- a/test/files/neg/t6446-missing.check +++ b/test/files/neg/t6446-missing.check @@ -29,4 +29,4 @@ inlinehandlers 24 optimization: inline exception handlers constopt 26 optimization: optimize null and other constants dce 27 optimization: eliminate dead code jvm 28 generate JVM bytecode - terminal 29 The last phase in the compiler chain + terminal 29 the last phase during a compilation run diff --git a/test/files/neg/t6446-show-phases.check b/test/files/neg/t6446-show-phases.check index a1bf408506..73cbfb6659 100644 --- a/test/files/neg/t6446-show-phases.check +++ b/test/files/neg/t6446-show-phases.check @@ -28,4 +28,4 @@ inlinehandlers 24 optimization: inline exception handlers constopt 26 optimization: optimize null and other constants dce 27 optimization: eliminate dead code jvm 28 generate JVM bytecode - terminal 29 The last phase in the compiler chain + terminal 29 the last phase during a compilation run diff --git a/test/files/neg/t7494-no-options.check b/test/files/neg/t7494-no-options.check index c197d2a671..efc91a6215 100644 --- a/test/files/neg/t7494-no-options.check +++ b/test/files/neg/t7494-no-options.check @@ -30,4 +30,4 @@ inlinehandlers 24 optimization: inline exception handlers dce 27 optimization: eliminate dead code jvm 28 generate JVM bytecode ploogin 29 A sample phase that does so many things it's kind of hard... - terminal 30 The last phase in the compiler chain + terminal 30 the last phase during a compilation run diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check index 61b947214c..cc325cafc0 100644 --- a/test/files/run/programmatic-main.check +++ b/test/files/run/programmatic-main.check @@ -28,5 +28,5 @@ inlinehandlers 24 optimization: inline exception handlers constopt 26 optimization: optimize null and other constants dce 27 optimization: eliminate dead code jvm 28 generate JVM bytecode - terminal 29 The last phase in the compiler chain + terminal 29 the last phase during a compilation run -- cgit v1.2.3 From f3731f9ace5d3d5e213ea786fe0027ea66c5358b Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 25 Jul 2013 19:52:15 -0700 Subject: SI-7622 Plugins can be not enabled Plugins can interrogate options and declare themselves not enabled. The plugin itself can return false from its init if the options do not compute. A plugin phase component can declare itself not enabled, same as an internal phase. No one exploits this facility at this commit. --- src/compiler/scala/tools/nsc/plugins/Plugin.scala | 29 ++++++++++++++++++---- .../scala/tools/nsc/plugins/PluginComponent.scala | 6 ++--- src/compiler/scala/tools/nsc/plugins/Plugins.scala | 25 ++++++------------- test/files/neg/t7494-no-options.check | 2 +- 4 files changed, 35 insertions(+), 27 deletions(-) (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 4fd6ba7d9d..1578caff26 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -41,12 +41,31 @@ abstract class Plugin { */ val global: Global - /** Handle any plugin-specific options. The `-P:plugname:` part - * will not be present. + def options: List[String] = { + // Process plugin options of form plugin:option + def namec = name + ":" + global.settings.pluginOptions.value filter (_ startsWith namec) map (_ stripPrefix namec) + } + + /** Handle any plugin-specific options. + * The user writes `-P:plugname:opt1,opt2`, + * but the plugin sees `List(opt1, opt2)`. + * The plugin can opt out of further processing + * by returning false. For example, if the plugin + * has an "enable" flag, now would be a good time + * to sit on the bench. + * @param options plugin arguments + * @param error error function + * @return true to continue, or false to opt out */ - def processOptions(options: List[String], error: String => Unit) { - if (!options.isEmpty) - error("Error: " + name + " has no options") + def init(options: List[String], error: String => Unit): Boolean = { + processOptions(options, error) + true + } + + @deprecated("use Plugin#init instead", since="2.11") + def processOptions(options: List[String], error: String => Unit): Unit = { + if (!options.isEmpty) error(s"Error: $name takes no options") } /** A description of this plugin's options, suitable as a response diff --git a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala index c6e1af7ea4..a6df08c331 100644 --- a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala +++ b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala @@ -15,12 +15,10 @@ package plugins */ abstract class PluginComponent extends SubComponent { - /** Internal flag to tell external from internal phases */ + /** By definition, plugin phases are externally provided. */ final override val internal = false - /** Phases supplied by plugins should not have to supply the - * runsRightAfter constraint, but can override it. - */ + /** Only plugins are granted a reprieve from specifying whether they follow. */ val runsRightAfter: Option[String] = None /** Useful for -Xshow-phases. */ diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index 8f7794fa90..4769705404 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -78,27 +78,18 @@ trait Plugins { val plugs = pick(roughPluginsList, Set(), (phasesSet map (_.phaseName)).toSet) - /* Verify requirements are present. */ + // Verify required plugins are present. for (req <- settings.require.value ; if !(plugs exists (_.name == req))) globalError("Missing required plugin: " + req) - /* Process plugin options. */ - def namec(plug: Plugin) = plug.name + ":" - def optList(xs: List[String], p: Plugin) = xs filter (_ startsWith namec(p)) - def doOpts(p: Plugin): List[String] = - optList(settings.pluginOptions.value, p) map (_ stripPrefix namec(p)) + // Verify no non-existent plugin given with -P + for { + opt <- settings.pluginOptions.value + if !(plugs exists (opt startsWith _.name + ":")) + } globalError("bad option: -P:" + opt) - for (p <- plugs) { - val opts = doOpts(p) - if (!opts.isEmpty) - p.processOptions(opts, globalError) - } - - /* Verify no non-existent plugin given with -P */ - for (opt <- settings.pluginOptions.value ; if plugs forall (p => optList(List(opt), p).isEmpty)) - globalError("bad option: -P:" + opt) - - plugs + // Plugins may opt out, unless we just want to show info + plugs filter (p => p.init(p.options, globalError) || (settings.debug && settings.isInfo)) } lazy val plugins: List[Plugin] = loadPlugins() diff --git a/test/files/neg/t7494-no-options.check b/test/files/neg/t7494-no-options.check index efc91a6215..04fbf0ec72 100644 --- a/test/files/neg/t7494-no-options.check +++ b/test/files/neg/t7494-no-options.check @@ -1,4 +1,4 @@ -error: Error: ploogin has no options +error: Error: ploogin takes no options phase name id description ---------- -- ----------- parser 1 parse source into ASTs, perform simple desugaring -- cgit v1.2.3 From 1683c95e159006d40a8458d29ef266ca741752c7 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 25 Jul 2013 12:58:56 -0700 Subject: SI-7622 Clean Up Phase Assembly Let optimiser components and continuations plugin opt-out when required flags are not set. Wasted time on a whitespace error in check file, so let --debug dump the processed check file and its diff. --- .../tools/nsc/backend/opt/ClosureElimination.scala | 2 + .../nsc/backend/opt/ConstantOptimization.scala | 2 + .../nsc/backend/opt/DeadCodeElimination.scala | 2 + .../nsc/backend/opt/InlineExceptionHandlers.scala | 2 + .../scala/tools/nsc/backend/opt/Inliners.scala | 2 + .../plugin/scala/tools/selectivecps/CPSUtils.scala | 2 +- .../tools/selectivecps/SelectiveCPSPlugin.scala | 43 +++++++------ .../scala/tools/partest/IcodeComparison.scala | 73 ++++++++++++++++++++++ test/files/neg/t6446-additional.check | 6 ++ test/files/neg/t6446-missing.check | 5 ++ test/files/neg/t6446-show-phases.check | 5 ++ test/files/neg/t7494-no-options.check | 6 ++ test/files/neg/t7622-cyclic-dependency.check | 1 + .../neg/t7622-cyclic-dependency/ThePlugin.scala | 40 ++++++++++++ .../neg/t7622-cyclic-dependency/sample_2.flags | 1 + .../neg/t7622-cyclic-dependency/sample_2.scala | 6 ++ .../neg/t7622-cyclic-dependency/scalac-plugin.xml | 5 ++ test/files/neg/t7622-missing-dependency.check | 2 + .../neg/t7622-missing-dependency/ThePlugin.scala | 33 ++++++++++ .../neg/t7622-missing-dependency/sample_2.flags | 1 + .../neg/t7622-missing-dependency/sample_2.scala | 6 ++ .../neg/t7622-missing-dependency/scalac-plugin.xml | 5 ++ test/files/neg/t7622-missing-required.check | 2 + test/files/neg/t7622-missing-required.flags | 1 + test/files/neg/t7622-missing-required.scala | 4 ++ test/files/neg/t7622-multi-followers.check | 1 + .../neg/t7622-multi-followers/ThePlugin.scala | 44 +++++++++++++ .../files/neg/t7622-multi-followers/sample_2.flags | 1 + .../files/neg/t7622-multi-followers/sample_2.scala | 6 ++ .../neg/t7622-multi-followers/scalac-plugin.xml | 5 ++ test/files/run/inline-ex-handlers.scala | 4 +- test/files/run/programmatic-main.check | 9 +-- test/files/run/t5313.scala | 6 +- test/files/run/t6102.check | 2 + test/files/run/t6102.flags | 2 +- test/files/run/t6288b-jump-position.scala | 9 +-- test/files/run/t6955.check | 1 - test/files/run/t6955.scala | 12 +++- test/files/run/t6956.check | 1 - test/files/run/t6956.scala | 13 ++-- test/files/run/test-cpp.scala | 4 +- .../neg/t7494-cyclic-dependency/ThePlugin.scala | 41 ------------ .../neg/t7494-cyclic-dependency/sample_2.flags | 1 - .../neg/t7494-cyclic-dependency/sample_2.scala | 6 -- .../neg/t7494-cyclic-dependency/scalac-plugin.xml | 5 -- 45 files changed, 326 insertions(+), 104 deletions(-) create mode 100644 src/partest-extras/scala/tools/partest/IcodeComparison.scala create mode 100644 test/files/neg/t7622-cyclic-dependency.check create mode 100644 test/files/neg/t7622-cyclic-dependency/ThePlugin.scala create mode 100644 test/files/neg/t7622-cyclic-dependency/sample_2.flags create mode 100644 test/files/neg/t7622-cyclic-dependency/sample_2.scala create mode 100644 test/files/neg/t7622-cyclic-dependency/scalac-plugin.xml create mode 100644 test/files/neg/t7622-missing-dependency.check create mode 100644 test/files/neg/t7622-missing-dependency/ThePlugin.scala create mode 100644 test/files/neg/t7622-missing-dependency/sample_2.flags create mode 100644 test/files/neg/t7622-missing-dependency/sample_2.scala create mode 100644 test/files/neg/t7622-missing-dependency/scalac-plugin.xml create mode 100644 test/files/neg/t7622-missing-required.check create mode 100644 test/files/neg/t7622-missing-required.flags create mode 100644 test/files/neg/t7622-missing-required.scala create mode 100644 test/files/neg/t7622-multi-followers.check create mode 100644 test/files/neg/t7622-multi-followers/ThePlugin.scala create mode 100644 test/files/neg/t7622-multi-followers/sample_2.flags create mode 100644 test/files/neg/t7622-multi-followers/sample_2.scala create mode 100644 test/files/neg/t7622-multi-followers/scalac-plugin.xml delete mode 100644 test/files/run/t6955.check delete mode 100644 test/files/run/t6956.check delete mode 100644 test/pending/neg/t7494-cyclic-dependency/ThePlugin.scala delete mode 100644 test/pending/neg/t7494-cyclic-dependency/sample_2.flags delete mode 100644 test/pending/neg/t7494-cyclic-dependency/sample_2.scala delete mode 100644 test/pending/neg/t7494-cyclic-dependency/scalac-plugin.xml (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index bde17b28fc..c49f23852f 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -18,6 +18,8 @@ abstract class ClosureElimination extends SubComponent { val phaseName = "closelim" + override val enabled: Boolean = settings.Xcloselim + /** Create a new phase */ override def newPhase(p: Phase) = new ClosureEliminationPhase(p) diff --git a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala index 43c8527f41..64a0727440 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala @@ -34,6 +34,8 @@ abstract class ConstantOptimization extends SubComponent { /** Create a new phase */ override def newPhase(p: Phase) = new ConstantOptimizationPhase(p) + override val enabled: Boolean = settings.YconstOptimization + /** * The constant optimization phase. */ diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 483bff6467..e373964987 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -22,6 +22,8 @@ abstract class DeadCodeElimination extends SubComponent { val phaseName = "dce" + override val enabled: Boolean = settings.Xdce + /** Create a new phase */ override def newPhase(p: Phase) = new DeadCodeEliminationPhase(p) diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index cecabda171..f4e97a91d8 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -57,6 +57,8 @@ abstract class InlineExceptionHandlers extends SubComponent { /** Create a new phase */ override def newPhase(p: Phase) = new InlineExceptionHandlersPhase(p) + override def enabled = settings.inlineHandlers + /** * Inlining Exception Handlers */ diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 09095879bf..181f4bde4e 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -49,6 +49,8 @@ abstract class Inliners extends SubComponent { val phaseName = "inliner" + override val enabled: Boolean = settings.inline + /** Debug - for timing the inliner. */ /**** private def timed[T](s: String, body: => T): T = { diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala index 29480576ea..98d0695865 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala @@ -8,7 +8,7 @@ trait CPSUtils { val global: Global import global._ - var cpsEnabled = false + val cpsEnabled: Boolean val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true" def vprintln(x: =>Any): Unit = if (verbose) println(x) diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala index d3b02d74f4..a7e82e949b 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala @@ -11,41 +11,44 @@ class SelectiveCPSPlugin(val global: Global) extends Plugin { val name = "continuations" val description = "applies selective cps conversion" - val anfPhase = new {val global = SelectiveCPSPlugin.this.global } with SelectiveANFTransform() { + val pluginEnabled = options contains "enable" + + val anfPhase = new { + val global = SelectiveCPSPlugin.this.global + val cpsEnabled = pluginEnabled + override val enabled = cpsEnabled + } with SelectiveANFTransform { val runsAfter = List("pickler") } - val cpsPhase = new {val global = SelectiveCPSPlugin.this.global } with SelectiveCPSTransform() { + val cpsPhase = new { + val global = SelectiveCPSPlugin.this.global + val cpsEnabled = pluginEnabled + override val enabled = cpsEnabled + } with SelectiveCPSTransform { val runsAfter = List("selectiveanf") override val runsBefore = List("uncurry") } val components = List[PluginComponent](anfPhase, cpsPhase) - val checker = new { val global: SelectiveCPSPlugin.this.global.type = SelectiveCPSPlugin.this.global } with CPSAnnotationChecker + val checker = new { + val global: SelectiveCPSPlugin.this.global.type = SelectiveCPSPlugin.this.global + val cpsEnabled = pluginEnabled + } with CPSAnnotationChecker + + // TODO don't muck up global with unused checkers global.addAnnotationChecker(checker.checker) global.analyzer.addAnalyzerPlugin(checker.plugin) global.log("instantiated cps plugin: " + this) - def setEnabled(flag: Boolean) = { - checker.cpsEnabled = flag - anfPhase.cpsEnabled = flag - cpsPhase.cpsEnabled = flag - } - - // TODO: require -enabled command-line flag - - override def processOptions(options: List[String], error: String => Unit) = { - var enabled = false - for (option <- options) { - if (option == "enable") { - enabled = true - } else { - error("Option not understood: "+option) - } + override def init(options: List[String], error: String => Unit) = { + options foreach { + case "enable" => // in initializer + case arg => error(s"Bad argument: $arg") } - setEnabled(enabled) + pluginEnabled } override val optionsHelp: Option[String] = diff --git a/src/partest-extras/scala/tools/partest/IcodeComparison.scala b/src/partest-extras/scala/tools/partest/IcodeComparison.scala new file mode 100644 index 0000000000..24b87e898f --- /dev/null +++ b/src/partest-extras/scala/tools/partest/IcodeComparison.scala @@ -0,0 +1,73 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.partest + +import scala.tools.partest.nest.FileManager.compareContents +import scala.compat.Platform.EOL + +/** A class for testing icode. All you need is this in a + * partest source file -- + * {{{ + * object Test extends IcodeComparison + * }}} + * -- and the generated output will be the icode for everything + * in that file. See scaladoc for possible customizations. + */ +abstract class IcodeComparison extends DirectTest { + /** The phase after which icode is printed. + * Override to check icode at a different point, + * but you can't print at a phase that is not enabled + * in this compiler run. Defaults to "icode". + */ + def printIcodeAfterPhase = "icode" + + /** When comparing the output of two phases, this is + * the other phase of interest, normally the preceding + * phase. Defaults to "icode" for tests of optimizer phases. + */ + def printSuboptimalIcodeAfterPhase = "icode" + + /** The source code to compile defaults to the test file. + * I.e., the test file compiles itself. For a comparison, + * the test file will be compiled three times. + */ + def code = testPath.slurp() + + /** By default, the test code is compiled with -usejavacp. */ + override def extraSettings: String = "-usejavacp" + + /** Compile the test code and return the contents of all + * (sorted) .icode files, which are immediately deleted. + * @param arg0 at least one arg is required + * @param args must include -Xprint-icode:phase + */ + def collectIcode(arg0: String, args: String*): List[String] = { + compile("-d" :: testOutput.path :: arg0 :: args.toList : _*) + val icodeFiles = testOutput.files.toList filter (_ hasExtension "icode") + + try icodeFiles sortBy (_.name) flatMap (f => f.lines.toList) + finally icodeFiles foreach (f => f.delete()) + } + + /** Collect icode at the default phase, `printIcodeAfterPhase`. */ + def collectIcode(): List[String] = collectIcode(s"-Xprint-icode:$printIcodeAfterPhase") + + /** Default show is showComparison. May be overridden for showIcode or similar. */ + def show() = showComparison() + + /** Compile the test code with and without optimization, and + * then print the diff of the icode. + */ + def showComparison() = { + val lines1 = collectIcode(s"-Xprint-icode:$printSuboptimalIcodeAfterPhase") + val lines2 = collectIcode("-optimise", s"-Xprint-icode:$printIcodeAfterPhase") + + println(compareContents(lines1, lines2)) + } + + /** Print icode at the default phase, `printIcodeAfterPhase`. */ + def showIcode() = println(collectIcode() mkString EOL) +} diff --git a/test/files/neg/t6446-additional.check b/test/files/neg/t6446-additional.check index be928095d3..6dfe072913 100755 --- a/test/files/neg/t6446-additional.check +++ b/test/files/neg/t6446-additional.check @@ -22,6 +22,7 @@ superaccessors 6 add super accessors in traits and nested classes mixin 20 mixin composition cleanup 21 platform-specific cleanups, generate reflective calls icode 22 generate portable intermediate code +#partest -optimise inliner 23 optimization: do inlining inlinehandlers 24 optimization: inline exception handlers closelim 25 optimization: eliminate uncalled closures @@ -30,3 +31,8 @@ inlinehandlers 24 optimization: inline exception handlers jvm 28 generate JVM bytecode ploogin 29 A sample phase that does so many things it's kind of hard... terminal 30 the last phase during a compilation run +#partest !-optimise + jvm 23 generate JVM bytecode + ploogin 24 A sample phase that does so many things it's kind of hard... + terminal 25 the last phase during a compilation run +#partest diff --git a/test/files/neg/t6446-missing.check b/test/files/neg/t6446-missing.check index 8ede1bd260..d4afa9b630 100755 --- a/test/files/neg/t6446-missing.check +++ b/test/files/neg/t6446-missing.check @@ -23,6 +23,10 @@ superaccessors 6 add super accessors in traits and nested classes mixin 20 mixin composition cleanup 21 platform-specific cleanups, generate reflective calls icode 22 generate portable intermediate code +#partest !-optimise + jvm 23 generate JVM bytecode + terminal 24 the last phase during a compilation run +#partest -optimise inliner 23 optimization: do inlining inlinehandlers 24 optimization: inline exception handlers closelim 25 optimization: eliminate uncalled closures @@ -30,3 +34,4 @@ inlinehandlers 24 optimization: inline exception handlers dce 27 optimization: eliminate dead code jvm 28 generate JVM bytecode terminal 29 the last phase during a compilation run +#partest diff --git a/test/files/neg/t6446-show-phases.check b/test/files/neg/t6446-show-phases.check index 73cbfb6659..10a9e08b86 100644 --- a/test/files/neg/t6446-show-phases.check +++ b/test/files/neg/t6446-show-phases.check @@ -22,6 +22,10 @@ superaccessors 6 add super accessors in traits and nested classes mixin 20 mixin composition cleanup 21 platform-specific cleanups, generate reflective calls icode 22 generate portable intermediate code +#partest !-optimise + jvm 23 generate JVM bytecode + terminal 24 the last phase during a compilation run +#partest -optimise inliner 23 optimization: do inlining inlinehandlers 24 optimization: inline exception handlers closelim 25 optimization: eliminate uncalled closures @@ -29,3 +33,4 @@ inlinehandlers 24 optimization: inline exception handlers dce 27 optimization: eliminate dead code jvm 28 generate JVM bytecode terminal 29 the last phase during a compilation run +#partest diff --git a/test/files/neg/t7494-no-options.check b/test/files/neg/t7494-no-options.check index 04fbf0ec72..0bde84c96c 100644 --- a/test/files/neg/t7494-no-options.check +++ b/test/files/neg/t7494-no-options.check @@ -23,6 +23,11 @@ superaccessors 6 add super accessors in traits and nested classes mixin 20 mixin composition cleanup 21 platform-specific cleanups, generate reflective calls icode 22 generate portable intermediate code +#partest !-optimise + jvm 23 generate JVM bytecode + ploogin 24 A sample phase that does so many things it's kind of hard... + terminal 25 the last phase during a compilation run +#partest -optimise inliner 23 optimization: do inlining inlinehandlers 24 optimization: inline exception handlers closelim 25 optimization: eliminate uncalled closures @@ -31,3 +36,4 @@ inlinehandlers 24 optimization: inline exception handlers jvm 28 generate JVM bytecode ploogin 29 A sample phase that does so many things it's kind of hard... terminal 30 the last phase during a compilation run +#partest diff --git a/test/files/neg/t7622-cyclic-dependency.check b/test/files/neg/t7622-cyclic-dependency.check new file mode 100644 index 0000000000..3546964f5f --- /dev/null +++ b/test/files/neg/t7622-cyclic-dependency.check @@ -0,0 +1 @@ +error: Cycle in phase dependencies detected at cyclicdependency1, created phase-cycle.dot diff --git a/test/files/neg/t7622-cyclic-dependency/ThePlugin.scala b/test/files/neg/t7622-cyclic-dependency/ThePlugin.scala new file mode 100644 index 0000000000..7a905ae32d --- /dev/null +++ b/test/files/neg/t7622-cyclic-dependency/ThePlugin.scala @@ -0,0 +1,40 @@ +package scala.test.plugins + +import scala.tools.nsc +import nsc.Global +import nsc.Phase +import nsc.plugins.Plugin +import nsc.plugins.PluginComponent + +class ThePlugin(val global: Global) extends Plugin { + import global._ + + val name = "cyclicdependency" + val description = "Declares two phases that have a cyclic dependency" + val components = List[PluginComponent](thePhase1,thePhase2) + + private object thePhase1 extends PluginComponent { + val global = ThePlugin.this.global + + val runsAfter = List[String]("tailcalls","cyclicdependency2") + + val phaseName = ThePlugin.this.name + "1" + + def newPhase(prev: Phase) = new ThePhase(prev, phaseName) + } + + private object thePhase2 extends PluginComponent { + val global = ThePlugin.this.global + + val runsAfter = List[String]("dce","cyclicdependency1") + + val phaseName = ThePlugin.this.name + "2" + + def newPhase(prev: Phase) = new ThePhase(prev, phaseName) + } + + private class ThePhase(prev: Phase, val name: String) extends Phase(prev) { + def run {} + } +} + diff --git a/test/files/neg/t7622-cyclic-dependency/sample_2.flags b/test/files/neg/t7622-cyclic-dependency/sample_2.flags new file mode 100644 index 0000000000..db25b88a12 --- /dev/null +++ b/test/files/neg/t7622-cyclic-dependency/sample_2.flags @@ -0,0 +1 @@ +-Xplugin:. -Xplugin-require:cyclicdependency diff --git a/test/files/neg/t7622-cyclic-dependency/sample_2.scala b/test/files/neg/t7622-cyclic-dependency/sample_2.scala new file mode 100644 index 0000000000..73cdc64e40 --- /dev/null +++ b/test/files/neg/t7622-cyclic-dependency/sample_2.scala @@ -0,0 +1,6 @@ + +package sample + +// just a sample that is compiled with the sample plugin enabled +object Sample extends App { +} diff --git a/test/files/neg/t7622-cyclic-dependency/scalac-plugin.xml b/test/files/neg/t7622-cyclic-dependency/scalac-plugin.xml new file mode 100644 index 0000000000..2558d6fd03 --- /dev/null +++ b/test/files/neg/t7622-cyclic-dependency/scalac-plugin.xml @@ -0,0 +1,5 @@ + + ignored + scala.test.plugins.ThePlugin + + diff --git a/test/files/neg/t7622-missing-dependency.check b/test/files/neg/t7622-missing-dependency.check new file mode 100644 index 0000000000..a0d0e30870 --- /dev/null +++ b/test/files/neg/t7622-missing-dependency.check @@ -0,0 +1,2 @@ +error: Phase 'myplugin' requires: List(missing) +one error found diff --git a/test/files/neg/t7622-missing-dependency/ThePlugin.scala b/test/files/neg/t7622-missing-dependency/ThePlugin.scala new file mode 100644 index 0000000000..a87cbb8e45 --- /dev/null +++ b/test/files/neg/t7622-missing-dependency/ThePlugin.scala @@ -0,0 +1,33 @@ +package scala.test.plugins + +import scala.tools.nsc +import nsc.Global +import nsc.Phase +import nsc.plugins.Plugin +import nsc.plugins.PluginComponent + +class ThePlugin(val global: Global) extends Plugin { + import global._ + + val name = "myplugin" + val description = "Declares one plugin with a missing requirement" + val components = List[PluginComponent](thePhase) + + private object thePhase extends PluginComponent { + val global = ThePlugin.this.global + + val runsAfter = List[String]("typer") + + val phaseName = ThePlugin.this.name + + override val requires = List("missing") + + def newPhase(prev: Phase) = new ThePhase(prev) + } + + private class ThePhase(prev: Phase) extends Phase(prev) { + def name = thePhase.phaseName + def run {} + } +} + diff --git a/test/files/neg/t7622-missing-dependency/sample_2.flags b/test/files/neg/t7622-missing-dependency/sample_2.flags new file mode 100644 index 0000000000..d69035100e --- /dev/null +++ b/test/files/neg/t7622-missing-dependency/sample_2.flags @@ -0,0 +1 @@ +-Xplugin:. -Xplugin-require:myplugin diff --git a/test/files/neg/t7622-missing-dependency/sample_2.scala b/test/files/neg/t7622-missing-dependency/sample_2.scala new file mode 100644 index 0000000000..73cdc64e40 --- /dev/null +++ b/test/files/neg/t7622-missing-dependency/sample_2.scala @@ -0,0 +1,6 @@ + +package sample + +// just a sample that is compiled with the sample plugin enabled +object Sample extends App { +} diff --git a/test/files/neg/t7622-missing-dependency/scalac-plugin.xml b/test/files/neg/t7622-missing-dependency/scalac-plugin.xml new file mode 100644 index 0000000000..3c14061dce --- /dev/null +++ b/test/files/neg/t7622-missing-dependency/scalac-plugin.xml @@ -0,0 +1,5 @@ + + myplugin + scala.test.plugins.ThePlugin + + diff --git a/test/files/neg/t7622-missing-required.check b/test/files/neg/t7622-missing-required.check new file mode 100644 index 0000000000..5982178581 --- /dev/null +++ b/test/files/neg/t7622-missing-required.check @@ -0,0 +1,2 @@ +error: Missing required plugin: special-plugin +one error found diff --git a/test/files/neg/t7622-missing-required.flags b/test/files/neg/t7622-missing-required.flags new file mode 100644 index 0000000000..65deac6feb --- /dev/null +++ b/test/files/neg/t7622-missing-required.flags @@ -0,0 +1 @@ +-Xplugin-require:special-plugin diff --git a/test/files/neg/t7622-missing-required.scala b/test/files/neg/t7622-missing-required.scala new file mode 100644 index 0000000000..a0ba487b24 --- /dev/null +++ b/test/files/neg/t7622-missing-required.scala @@ -0,0 +1,4 @@ + +// the amazing features of this trait +// are unlocked by compiling with a special plugin. +trait Amazing diff --git a/test/files/neg/t7622-multi-followers.check b/test/files/neg/t7622-multi-followers.check new file mode 100644 index 0000000000..5cda422ff0 --- /dev/null +++ b/test/files/neg/t7622-multi-followers.check @@ -0,0 +1 @@ +error: Phase parser has too many followers: multi1,multi2; created phase-order.dot diff --git a/test/files/neg/t7622-multi-followers/ThePlugin.scala b/test/files/neg/t7622-multi-followers/ThePlugin.scala new file mode 100644 index 0000000000..e7a49a9be6 --- /dev/null +++ b/test/files/neg/t7622-multi-followers/ThePlugin.scala @@ -0,0 +1,44 @@ +package scala.test.plugins + +import scala.tools.nsc +import nsc.Global +import nsc.Phase +import nsc.plugins.Plugin +import nsc.plugins.PluginComponent + +class ThePlugin(val global: Global) extends Plugin { + import global._ + + val name = "multi" + val description = "Declares two phases that both follow parser" + val components = List[PluginComponent](thePhase1,thePhase2) + + private object thePhase1 extends PluginComponent { + val global = ThePlugin.this.global + + val runsAfter = List[String]() + + override val runsRightAfter = Some("parser") + + val phaseName = ThePlugin.this.name + "1" + + def newPhase(prev: Phase) = new ThePhase(prev, phaseName) + } + + private object thePhase2 extends PluginComponent { + val global = ThePlugin.this.global + + val runsAfter = List[String]() + + override val runsRightAfter = Some("parser") + + val phaseName = ThePlugin.this.name + "2" + + def newPhase(prev: Phase) = new ThePhase(prev, phaseName) + } + + private class ThePhase(prev: Phase, val name: String) extends Phase(prev) { + def run {} + } +} + diff --git a/test/files/neg/t7622-multi-followers/sample_2.flags b/test/files/neg/t7622-multi-followers/sample_2.flags new file mode 100644 index 0000000000..d2e83e9723 --- /dev/null +++ b/test/files/neg/t7622-multi-followers/sample_2.flags @@ -0,0 +1 @@ +-Xplugin:. -Xplugin-require:multi diff --git a/test/files/neg/t7622-multi-followers/sample_2.scala b/test/files/neg/t7622-multi-followers/sample_2.scala new file mode 100644 index 0000000000..73cdc64e40 --- /dev/null +++ b/test/files/neg/t7622-multi-followers/sample_2.scala @@ -0,0 +1,6 @@ + +package sample + +// just a sample that is compiled with the sample plugin enabled +object Sample extends App { +} diff --git a/test/files/neg/t7622-multi-followers/scalac-plugin.xml b/test/files/neg/t7622-multi-followers/scalac-plugin.xml new file mode 100644 index 0000000000..2558d6fd03 --- /dev/null +++ b/test/files/neg/t7622-multi-followers/scalac-plugin.xml @@ -0,0 +1,5 @@ + + ignored + scala.test.plugins.ThePlugin + + diff --git a/test/files/run/inline-ex-handlers.scala b/test/files/run/inline-ex-handlers.scala index 33e794b940..964594d258 100644 --- a/test/files/run/inline-ex-handlers.scala +++ b/test/files/run/inline-ex-handlers.scala @@ -1,6 +1,6 @@ -import scala.tools.partest.IcodeTest +import scala.tools.partest.IcodeComparison -object Test extends IcodeTest { +object Test extends IcodeComparison { override def printIcodeAfterPhase = "inlinehandlers" } diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check index cc325cafc0..a6e53fbe92 100644 --- a/test/files/run/programmatic-main.check +++ b/test/files/run/programmatic-main.check @@ -22,11 +22,6 @@ superaccessors 6 add super accessors in traits and nested classes mixin 20 mixin composition cleanup 21 platform-specific cleanups, generate reflective calls icode 22 generate portable intermediate code - inliner 23 optimization: do inlining -inlinehandlers 24 optimization: inline exception handlers - closelim 25 optimization: eliminate uncalled closures - constopt 26 optimization: optimize null and other constants - dce 27 optimization: eliminate dead code - jvm 28 generate JVM bytecode - terminal 29 the last phase during a compilation run + jvm 23 generate JVM bytecode + terminal 24 the last phase during a compilation run diff --git a/test/files/run/t5313.scala b/test/files/run/t5313.scala index febfd9c3ed..4cbc29ba5d 100644 --- a/test/files/run/t5313.scala +++ b/test/files/run/t5313.scala @@ -1,6 +1,6 @@ -import scala.tools.partest.IcodeTest +import scala.tools.partest.IcodeComparison -object Test extends IcodeTest { +object Test extends IcodeComparison { override def printIcodeAfterPhase = "dce" override def extraSettings: String = super.extraSettings + " -optimize" @@ -48,7 +48,7 @@ object Test extends IcodeTest { override def show() { val storeLocal = "STORE_LOCAL" - val lines1 = collectIcode("") filter (_ contains storeLocal) map (x => x.drop(x.indexOf(storeLocal))) + val lines1 = collectIcode() filter (_ contains storeLocal) map (x => x.drop(x.indexOf(storeLocal))) println(lines1 mkString "\n") } } diff --git a/test/files/run/t6102.check b/test/files/run/t6102.check index 97e455647b..4e8efa7b6d 100644 --- a/test/files/run/t6102.check +++ b/test/files/run/t6102.check @@ -20,10 +20,12 @@ [running phase mixin on t6102.scala] [running phase cleanup on t6102.scala] [running phase icode on t6102.scala] +#partest -optimise [running phase inliner on t6102.scala] [running phase inlinehandlers on t6102.scala] [running phase closelim on t6102.scala] [running phase constopt on t6102.scala] +#partest [running phase dce on t6102.scala] [running phase jvm on icode] hello diff --git a/test/files/run/t6102.flags b/test/files/run/t6102.flags index 72fe7b1aa0..726e2a997f 100644 --- a/test/files/run/t6102.flags +++ b/test/files/run/t6102.flags @@ -1 +1 @@ - -Ydead-code -Ydebug -Xfatal-warnings +-Ydead-code -Ydebug -Xfatal-warnings diff --git a/test/files/run/t6288b-jump-position.scala b/test/files/run/t6288b-jump-position.scala index e22a1ab120..c5f3bbe788 100644 --- a/test/files/run/t6288b-jump-position.scala +++ b/test/files/run/t6288b-jump-position.scala @@ -1,6 +1,6 @@ -import scala.tools.partest.IcodeTest +import scala.tools.partest.IcodeComparison -object Test extends IcodeTest { +object Test extends IcodeComparison { override def code = """object Case3 { // 01 | def unapply(z: Any): Option[Int] = Some(-1) // 02 @@ -15,8 +15,5 @@ object Test extends IcodeTest { | } |}""".stripMargin - override def show() { - val lines1 = collectIcode("") - println(lines1 mkString "\n") - } + override def show() = showIcode() } diff --git a/test/files/run/t6955.check b/test/files/run/t6955.check deleted file mode 100644 index 0cfbf08886..0000000000 --- a/test/files/run/t6955.check +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/test/files/run/t6955.scala b/test/files/run/t6955.scala index 980aa420cc..329af688e4 100644 --- a/test/files/run/t6955.scala +++ b/test/files/run/t6955.scala @@ -1,4 +1,4 @@ -import scala.tools.partest.IcodeTest +import scala.tools.partest.IcodeComparison // this class should compile to code that uses switches (twice) class Switches { @@ -20,9 +20,15 @@ class Switches { } } -object Test extends IcodeTest { +object Test extends IcodeComparison { // ensure we get two switches out of this -- ignore the rest of the output for robustness // exclude the constant we emit for the "SWITCH ..." string below (we get the icode for all the code you see in this file) - override def show() = println(collectIcode("").filter(x => x.indexOf("SWITCH ...") >= 0 && x.indexOf("CONSTANT(") == -1).size) + override def show() = { + val expected = 2 + val actual = (collectIcode() filter { + x => x.indexOf("SWITCH ...") >= 0 && x.indexOf("CONSTANT(") == -1 + }).size + assert(actual == expected) + } } diff --git a/test/files/run/t6956.check b/test/files/run/t6956.check deleted file mode 100644 index 0cfbf08886..0000000000 --- a/test/files/run/t6956.check +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/test/files/run/t6956.scala b/test/files/run/t6956.scala index 4a6583ca45..3569adf483 100644 --- a/test/files/run/t6956.scala +++ b/test/files/run/t6956.scala @@ -1,4 +1,4 @@ -import scala.tools.partest.IcodeTest +import scala.tools.partest.IcodeComparison class Switches { private[this] final val ONE = 1 @@ -18,9 +18,14 @@ class Switches { } } -object Test extends IcodeTest { +object Test extends IcodeComparison { // ensure we get two switches out of this -- ignore the rest of the output for robustness // exclude the constant we emit for the "SWITCH ..." string below (we get the icode for all the code you see in this file) - override def show() = println(collectIcode("").filter(x => x.indexOf("SWITCH ...") >= 0 && x.indexOf("CONSTANT(") == -1).size) + override def show() = { + val expected = 2 + val actual = (collectIcode() filter { + x => x.indexOf("SWITCH ...") >= 0 && x.indexOf("CONSTANT(") == -1 + }).size + assert(actual == expected) + } } - diff --git a/test/files/run/test-cpp.scala b/test/files/run/test-cpp.scala index f9fa85c4d0..c6eda56776 100644 --- a/test/files/run/test-cpp.scala +++ b/test/files/run/test-cpp.scala @@ -12,9 +12,9 @@ * instead of 'l'. */ -import scala.tools.partest.IcodeTest +import scala.tools.partest.IcodeComparison -object Test extends IcodeTest { +object Test extends IcodeComparison { override def printIcodeAfterPhase = "dce" } diff --git a/test/pending/neg/t7494-cyclic-dependency/ThePlugin.scala b/test/pending/neg/t7494-cyclic-dependency/ThePlugin.scala deleted file mode 100644 index bd94ce60d7..0000000000 --- a/test/pending/neg/t7494-cyclic-dependency/ThePlugin.scala +++ /dev/null @@ -1,41 +0,0 @@ -package scala.test.plugins - -import scala.tools.nsc -import nsc.Global -import nsc.Phase -import nsc.plugins.Plugin -import nsc.plugins.PluginComponent - -class ThePlugin(val global: Global) extends Plugin { - import global._ - - val name = "cyclicdependency" - val description = "Declares two phases that have a cyclic dependency" - val components = List[PluginComponent](thePhase1,thePhase2) - - private object thePhase1 extends PluginComponent { - val global = ThePlugin.this.global - - val runsAfter = List[String]("tailcalls","cyclicdependency2") - - val phaseName = ThePlugin.this.name + "1" - - def newPhase(prev: Phase) = new ThePhase(prev) - } - - private object thePhase2 extends PluginComponent { - val global = ThePlugin.this.global - - val runsAfter = List[String]("dce","cyclicdependency1") - - val phaseName = ThePlugin.this.name + "2" - - def newPhase(prev: Phase) = new ThePhase(prev) - } - - private class ThePhase(prev: Phase) extends Phase(prev) { - def name = ThePlugin.this.name - def run {} - } -} - diff --git a/test/pending/neg/t7494-cyclic-dependency/sample_2.flags b/test/pending/neg/t7494-cyclic-dependency/sample_2.flags deleted file mode 100644 index db25b88a12..0000000000 --- a/test/pending/neg/t7494-cyclic-dependency/sample_2.flags +++ /dev/null @@ -1 +0,0 @@ --Xplugin:. -Xplugin-require:cyclicdependency diff --git a/test/pending/neg/t7494-cyclic-dependency/sample_2.scala b/test/pending/neg/t7494-cyclic-dependency/sample_2.scala deleted file mode 100644 index 73cdc64e40..0000000000 --- a/test/pending/neg/t7494-cyclic-dependency/sample_2.scala +++ /dev/null @@ -1,6 +0,0 @@ - -package sample - -// just a sample that is compiled with the sample plugin enabled -object Sample extends App { -} diff --git a/test/pending/neg/t7494-cyclic-dependency/scalac-plugin.xml b/test/pending/neg/t7494-cyclic-dependency/scalac-plugin.xml deleted file mode 100644 index 2558d6fd03..0000000000 --- a/test/pending/neg/t7494-cyclic-dependency/scalac-plugin.xml +++ /dev/null @@ -1,5 +0,0 @@ - - ignored - scala.test.plugins.ThePlugin - - -- cgit v1.2.3 From 5edf50dd5f50d921311795dc614c3c25425c783a Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 21 Aug 2013 04:34:07 -0700 Subject: SI-7622 Scaladoc and error message polish Restores the verbiage "run right after". --- src/compiler/scala/tools/nsc/Global.scala | 9 +++++++++ src/compiler/scala/tools/nsc/PhaseAssembly.scala | 2 +- test/files/neg/t7494-multi-right-after.check | 2 +- test/files/neg/t7622-multi-followers.check | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 3c8a4faa7d..4e750792cb 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -763,6 +763,15 @@ class Global(var currentSettings: Settings, var reporter: Reporter) phaseHelp("new flags", elliptically = false, fmt) } + /** Emit a verbose phase table. + * The table includes the phase id in the current assembly, + * or "oo" to indicate a skipped phase, or "xx" to indicate + * a disabled phase. + * + * @param title descriptive header + * @param elliptically whether to truncate the description with an ellipsis (...) + * @param describe how to describe a component + */ def phaseHelp(title: String, elliptically: Boolean, describe: SubComponent => String) = { val Limit = 16 // phase names should not be absurdly long val MaxCol = 80 // because some of us edit on green screens diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index 45502a19d6..996f6efe55 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -150,7 +150,7 @@ trait PhaseAssembly { } else if (sanity.length > 1) { dump("phase-order") val following = (sanity map (_.frm.phasename)).sorted mkString "," - throw new FatalError(s"Phase ${sanity.head.to.phasename} has too many followers: $following; created phase-order.dot") + throw new FatalError(s"Multiple phases want to run right after ${sanity.head.to.phasename}; followers: $following; created phase-order.dot") } else { val promote = hl.to.before.filter(e => (!e.hard)) diff --git a/test/files/neg/t7494-multi-right-after.check b/test/files/neg/t7494-multi-right-after.check index c0e0334aaf..151d177414 100644 --- a/test/files/neg/t7494-multi-right-after.check +++ b/test/files/neg/t7494-multi-right-after.check @@ -1 +1 @@ -error: Phase explicitouter has too many followers: erasure,multi-rafter; created phase-order.dot +error: Multiple phases want to run right after explicitouter; followers: erasure,multi-rafter; created phase-order.dot diff --git a/test/files/neg/t7622-multi-followers.check b/test/files/neg/t7622-multi-followers.check index 5cda422ff0..d123853a5b 100644 --- a/test/files/neg/t7622-multi-followers.check +++ b/test/files/neg/t7622-multi-followers.check @@ -1 +1 @@ -error: Phase parser has too many followers: multi1,multi2; created phase-order.dot +error: Multiple phases want to run right after parser; followers: multi1,multi2; created phase-order.dot -- cgit v1.2.3