Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept -Vprint:all, -Vprint:~tailcalls #10173

Merged
merged 2 commits into from Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 7 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 @@ -1536,7 +1536,7 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
informTime(globalPhase.description, phaseTimer.nanos)

// progress update
if ((settings.Xprint containsPhase globalPhase) || settings.printLate.value && runIsAt(cleanupPhase)) {
if (settings.Xprint.containsPhase(globalPhase) || settings.printLate.value && runIsAt(cleanupPhase)) {
// print trees
if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) nodePrinters.printAll()
else printAllUnits()
Expand Down
15 changes: 10 additions & 5 deletions src/compiler/scala/tools/nsc/settings/MutableSettings.scala
Expand Up @@ -945,14 +945,19 @@ 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}") ||
ph.next != null && containsName(s"~${ph.next.name}") // null if called during construction

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
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Expand Up @@ -499,7 +499,7 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
val showPhases = BooleanSetting("-Vphases", "Print a synopsis of compiler phases.")
.withAbbreviation("-Xshow-phases")
val Yposdebug = BooleanSetting("-Vpos", "Trace position validation.") withAbbreviation "-Ypos-debug"
val Xprint = PhasesSetting("-Vprint", "Print out program after")
val Xprint = PhasesSetting("-Vprint", "Print out program after (or ~phase for before and after)", "typer")
.withAbbreviation("-Xprint")
val Xprintpos = BooleanSetting("-Vprint-pos", "Print tree positions, as offsets.")
.withAbbreviation("-Xprint-pos")
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