Skip to content

Commit

Permalink
Accept -Vprint:all, -Vprint:~tailcalls
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed Oct 18, 2022
1 parent f8a5497 commit 6bc1a88
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 12 deletions.
19 changes: 12 additions & 7 deletions src/compiler/scala/tools/nsc/Global.scala
Expand Up @@ -1275,26 +1275,26 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
// 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 == "_" || isRange(s))
def isMulti(s: String) = s == "_" || s == "all" || isRange(s) || s.startsWith("~")
val tester = new ss.PhasesSetting("fake","fake")
for (p <- specs.flatten.to(Set)) {
tester.value = List(p)
val count =
if (including) first.iterator.count(tester.containsPhase(_))
else phaseDescriptors.count(pd => tester.contains(pd.phaseName))
else phaseDescriptors.count(pd => tester.contains(pd.phaseName) || tester.contains(s"~${pd.phaseName}"))
if (count == 0) runReporting.warning(NoPosition, s"'$p' specifies no phase", WarningCategory.Other, site = "")
if (count > 1 && !isSpecial(p)) runReporting.warning(NoPosition, s"'$p' selects $count phases", WarningCategory.Other, site = "")
if (!including && isSpecial(p)) globalError(s"-Yskip and -Ystop values must name phases: '$p'")
if (count > 1 && !isMulti(p)) runReporting.warning(NoPosition, s"'$p' selects $count phases", WarningCategory.Other, site = "")
if (!including && isMulti(p)) globalError(s"-Yskip and -Ystop values must name phases: '$p'")
tester.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
case s: ss.PhasesSetting if !exclusions.contains(s) => s.value
}
checkPhaseSettings(including = true, inclusions.toSeq: _*)
checkPhaseSettings(including = false, exclusions map (_.value): _*)
checkPhaseSettings(including = false, exclusions.map(_.value): _*)

// Report the overhead of statistics measurements per every run
if (settings.areStatisticsEnabled)
Expand Down Expand Up @@ -1535,8 +1535,13 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
if (timePhases)
informTime(globalPhase.description, phaseTimer.nanos)

// The phase name may be prefixed with "~". "-Vprint:~typer" intends printing before and after typer.
def printNow = {
settings.Xprint.containsPhase(globalPhase) ||
settings.Xprint.containsName(s"~${globalPhase.next.name}")
}
// progress update
if ((settings.Xprint containsPhase globalPhase) || settings.printLate.value && runIsAt(cleanupPhase)) {
if (printNow || settings.printLate.value && runIsAt(cleanupPhase)) {
// print trees
if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) nodePrinters.printAll()
else printAllUnits()
Expand Down
14 changes: 9 additions & 5 deletions src/compiler/scala/tools/nsc/settings/MutableSettings.scala
Expand Up @@ -945,14 +945,18 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)

def clear(): Unit = (v = Nil)

// we slightly abuse the usual meaning of "contains" here by returning
// true if our phase list contains "_", regardless of the incoming argument
/* True if the named phase is selected.
*
* A setting value "_" or "all" selects all phases by name.
*/
def contains(phName: String) = doAllPhases || containsName(phName)
def containsName(phName: String) = stringValues exists (phName startsWith _)
/* True if the given phase name matches the selection, possibly as prefixed "~name". */
def containsName(phName: String) = stringValues.exists(phName.startsWith(_))
def containsId(phaseId: Int) = phaseIdTest(phaseId)
def containsPhase(ph: Phase) = contains(ph.name) || containsId(ph.id)
/* True if the phase is selected by name or "all", or by id, or by prefixed "~name". */
def containsPhase(ph: Phase) = contains(ph.name) || containsId(ph.id) || containsName(s"~${ph.name}") || containsName(s"~${ph.next.name}")

def doAllPhases = stringValues.contains("_")
def doAllPhases = stringValues.exists(s => s == "_" || s == "all")
def unparse: List[String] = value.map(v => s"$name:$v")

withHelpSyntax(
Expand Down
48 changes: 48 additions & 0 deletions test/junit/scala/tools/nsc/settings/SettingsTest.scala
Expand Up @@ -354,6 +354,54 @@ class SettingsTest {
assertFalse(s.isInfo)
assertTrue(s.printArgs.isSetByUser)
}
@Test def `name-based phases setting accepts tilde prefix`: Unit = {
val start = new Phase(null) { def name = "start"; def run() = () }
val chunk = new Phase(start) { def name = "chunker"; def run() = () }
val clean = new Phase(chunk) { def name = "clean"; def run() = () }
val go = new Phase(clean) { def name = "go"; def run() = () }
val end = new Phase(go) { def name = "end"; def run() = () }
val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
val ps = new s.PhasesSetting("-Yp", descr="", default="")
s.allSettings(ps.name) = ps
val args = List("-Yp:clean,~chunker,3")
val (ok, residual) = s.processArguments(args, processAll = true)
assertTrue(ok)
assertTrue(residual.isEmpty)
assertTrue(ps.contains("clean"))
assertFalse(ps.contains("chunker"))
assertTrue(ps.contains("~chunker"))
assertFalse(ps.contains("start"))
assertFalse(ps.contains("end"))
assertTrue(ps.containsPhase(clean))
assertTrue(ps.containsPhase(chunk))
assertTrue(ps.containsPhase(start))
assertTrue(ps.containsPhase(start.next))
assertTrue(ps.contains(s"~${start.next.name}"))
assertTrue(ps.containsPhase(go))
assertTrue(ps.containsId(go.id))
assertFalse(ps.containsPhase(end))
assertFalse(ps.containsId(end.id))
}
@Test def `phases setting accepts all or underscore`: Unit = {
val start = new Phase(null) { def name = "start"; def run() = () }
def check(args: String*): MutableSettings#PhasesSetting = {
val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
val ps = new s.PhasesSetting("-Yp", descr="", default="")
s.allSettings(ps.name) = ps
val (ok, residual) = s.processArguments(args.toList, processAll = true)
assertTrue(ok)
assertTrue(residual.isEmpty)
ps
}
assertTrue(check("-Yp:start").containsPhase(start))
assertTrue(check("-Yp:start").contains("start"))
assertTrue(check("-Yp:start").containsName("start"))
assertTrue(check("-Yp:all").containsPhase(start))
assertTrue(check("-Yp:all").contains("start"))
assertFalse(check("-Yp:all").containsName("start"))
assertTrue(check("-Yp:_").containsPhase(start))
assertTrue(check("-Yp:junk,_").containsPhase(start))
}
}
object SettingsTest {
import language.implicitConversions
Expand Down

0 comments on commit 6bc1a88

Please sign in to comment.