Skip to content

-Vphases takes names to mark, -Vprint is typer #17563

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 4 additions & 21 deletions compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import typer.Typer
import typer.ImportInfo.withRootImports
import Decorators.*
import io.AbstractFile
import Phases.{unfusedPhases, Phase}
import Phases.{assemblePhases, unfusedPhases, Phase}

import sbt.interfaces.ProgressCallback

Expand Down Expand Up @@ -295,19 +295,12 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
report.echo(this.enrichErrorMessage(s"exception occurred while compiling ${files1.map(_.path)}"))
throw ex

/** TODO: There's a fundamental design problem here: We assemble phases using `fusePhases`
* when we first build the compiler. But we modify them with -Yskip, -Ystop
* on each run. That modification needs to either transform the tree structure,
* or we need to assemble phases on each run, and take -Yskip, -Ystop into
* account. I think the latter would be preferable.
*/
def compileSources(sources: List[SourceFile]): Unit =
if (sources forall (_.exists)) {
units = sources.map(CompilationUnit(_))
compileUnits()
}


def compileUnits(us: List[CompilationUnit]): Unit = {
units = us
compileUnits()
Expand All @@ -333,19 +326,9 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
then ActiveProfile(ctx.settings.VprofileDetails.value.max(0).min(1000))
else NoProfile

// If testing pickler, make sure to stop after pickling phase:
val stopAfter =
if (ctx.settings.YtestPickler.value) List("pickler")
else ctx.settings.YstopAfter.value

val runCtx = ctx.fresh
val runCtx = assemblePhases()
runCtx.setProfiler(Profiler())

val pluginPlan = ctx.base.addPluginPhases(ctx.base.phasePlan)
val phases = ctx.base.fusePhases(pluginPlan,
ctx.settings.Yskip.value, ctx.settings.YstopBefore.value, stopAfter, ctx.settings.Ycheck.value)
ctx.base.usePhases(phases, runCtx)

if ctx.settings.YnoDoubleBindings.value then
ctx.base.checkNoDoubleBindings = true

Expand All @@ -355,7 +338,7 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
var phasesWereAdjusted = false

var forceReachPhaseMaybe =
if (ctx.isBestEffort && phases.exists(_.phaseName == "typer")) Some("typer")
if (ctx.isBestEffort && allPhases.exists(_.phaseName == "typer")) Some("typer")
else None

for phase <- allPhases do
Expand All @@ -367,7 +350,7 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
profiler.onPhase(phase):
try units = phase.runOn(units)
catch case _: InterruptedException => cancelInterrupted()
if (ctx.settings.Vprint.value.containsPhase(phase))
for printAt <- ctx.settings.Vprint.userValue if printAt.containsPhase(phase) do
for (unit <- units)
def printCtx(unit: CompilationUnit) = phase.printingContext(
ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
Expand Down
27 changes: 20 additions & 7 deletions compiler/src/dotty/tools/dotc/config/CliCommand.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package config

import Settings.*
import core.Contexts.*
import core.Phases.assemblePhases
import printing.Highlighting
import transform.MegaPhase

import dotty.tools.dotc.util.chaining.*
import scala.PartialFunction.cond
Expand Down Expand Up @@ -115,9 +117,17 @@ trait CliCommand:

/** Used for the formatted output of -Xshow-phases */
protected def phasesMessage(using Context): String =
val phases = new Compiler().phases
val compiler = new Compiler()
ctx.initialize()
ctx.base.setPhasePlan(compiler.phases)
val runCtx = assemblePhases()
val phases = runCtx.base.allPhases
val texts = phases.iterator.map {
case mp: MegaPhase => mp.miniPhases.iterator.map(p => (p.phaseName, p.description)).toList
case p => (p.phaseName, p.description) :: Nil
}.toList
val formatter = Columnator("phase name", "description", maxField = 25)
formatter(phases.map(mega => mega.map(p => (p.phaseName, p.description))))
formatter(texts)

/** Provide usage feedback on argument summary, assuming that all settings
* are already applied in context.
Expand Down Expand Up @@ -156,12 +166,15 @@ trait CliCommand:
private def columnate(sb: StringBuilder, texts: List[List[(String, String)]])(using Context): Unit =
import Highlighting.*
val colors = Seq(Green(_), Yellow(_), Magenta(_), Cyan(_), Red(_))
val bolds = Seq(GreenB(_), YellowB(_), MagentaB(_), CyanB(_), RedB(_))
val nocolor = texts.length == 1
def color(index: Int): String => Highlight = if nocolor then NoColor(_) else colors(index % colors.length)
def colorB(index: Int): String => Highlight = if nocolor then NoColor(_) else bolds(index % colors.length)
val maxCol = ctx.settings.pageWidth.value
val field1 = maxField.min(texts.flatten.map(_._1.length).filter(_ < maxField).max) // widest field under maxField
val field2 = if field1 + separation + maxField < maxCol then maxCol - field1 - separation else 0 // skinny window -> terminal wrap
val separator = " " * separation
def toMark(name: String) = ctx.settings.Vphases.value.exists(s => name.toLowerCase.contains(s.toLowerCase))
def separator(name: String) = if toMark(name) then "->" + " " * (separation - 2) else " " * separation
val EOL = "\n"
def formatField1(text: String): String = if text.length <= field1 then text.padLeft(field1) else text + EOL + "".padLeft(field1)
def formatField2(text: String): String =
Expand All @@ -170,15 +183,15 @@ trait CliCommand:
else
fld.lastIndexOf(" ", field2) match
case -1 => List(fld)
case i => val (prefix, rest) = fld.splitAt(i) ; prefix :: loopOverField2(rest.trim)
text.split("\n").toList.flatMap(loopOverField2).filter(_.nonEmpty).mkString(EOL + "".padLeft(field1) + separator)
case i => val (prefix, rest) = fld.splitAt(i); prefix :: loopOverField2(rest.trim)
text.split("\n").toList.flatMap(loopOverField2).filter(_.nonEmpty).mkString(EOL + "".padLeft(field1) + separator("no-phase"))
end formatField2
def format(first: String, second: String, index: Int, colorPicker: Int => String => Highlight) =
sb.append(colorPicker(index)(formatField1(first)).show)
.append(separator)
.append(colorPicker(index)(separator(first)).show)
.append(formatField2(second))
.append(EOL): Unit
def fancy(first: String, second: String, index: Int) = format(first, second, index, color)
def fancy(first: String, second: String, index: Int) = format(first, second, index, if toMark(first) then colorB else color)
def plain(first: String, second: String) = format(first, second, 0, _ => NoColor(_))

if heading1.nonEmpty then
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/config/CompilerCommand.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ abstract class CompilerCommand extends CliCommand:
else if (settings.Xhelp.value) xusageMessage
else if (settings.Yhelp.value) yusageMessage
else if (settings.showPlugins.value) ctx.base.pluginDescriptions
else if (settings.XshowPhases.value) phasesMessage
else if settings.Vphases.isPresent then phasesMessage
else ""

final def isHelpFlag(using settings: ConcreteSettings)(using SettingsState): Boolean =
final def isHelpFlag(using settings: ConcreteSettings)(using ss: SettingsState): Boolean =
import settings.*
val flags = Set(help, Vhelp, Whelp, Xhelp, Yhelp, showPlugins, XshowPhases)
flags.exists(_.value) || allSettings.exists(isHelping)
val flags = Set(help, Vhelp, Whelp, Xhelp, Yhelp, showPlugins)
flags.exists(_.value) || Vphases.isPresentIn(ss) || allSettings.exists(isHelping)
10 changes: 3 additions & 7 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ trait CommonScalaSettings:
val explainTypes: Setting[Boolean] = BooleanSetting(RootSetting, "explain-types", "Explain type errors in more detail (deprecated, use -explain instead).", aliases = List("--explain-types", "-explaintypes"))
val explainCyclic: Setting[Boolean] = BooleanSetting(RootSetting, "explain-cyclic", "Explain cyclic reference errors in more detail.", aliases = List("--explain-cyclic"))
val unchecked: Setting[Boolean] = BooleanSetting(RootSetting, "unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked"))
val language: Setting[List[ChoiceWithHelp[String]]] = MultiChoiceHelpSetting(RootSetting, "language", "feature", "Enable one or more language features.", choices = ScalaSettingsProperties.supportedLanguageFeatures, legacyChoices = ScalaSettingsProperties.legacyLanguageFeatures, default = Nil, aliases = List("--language"))
val language: Setting[List[ChoiceWithHelp[String]]] = MultiChoiceHelpSetting(RootSetting, "language", "feature", "Enable one or more language features.", choices = ScalaSettingsProperties.supportedLanguageFeatures, legacyChoices = ScalaSettingsProperties.legacyLanguageFeatures, aliases = List("--language"))
val experimental: Setting[Boolean] = BooleanSetting(RootSetting, "experimental", "Annotate all top-level definitions with @experimental. This enables the use of experimental features anywhere in the project.")
val preview: Setting[Boolean] = BooleanSetting(RootSetting, "preview", "Enable the use of preview features anywhere in the project.")

Expand Down Expand Up @@ -144,9 +144,8 @@ private sealed trait PluginSettings:
private sealed trait VerboseSettings:
self: SettingGroup =>
val Vhelp: Setting[Boolean] = BooleanSetting(VerboseSetting, "V", "Print a synopsis of verbose options.")
val Vprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", aliases = List("-Xprint"))
val XshowPhases: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vphases", "List compiler phases.", aliases = List("-Xshow-phases"))

val Vprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", default = "typer", aliases = List("-Xprint"))
val Vphases: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vphases", "List compiler phases.", default = "none", aliases = List("-Xshow-phases"))
val Vprofile: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vprofile", "Show metrics about sources and internal representations to estimate compile-time complexity.")
val VprofileSortedBy = ChoiceSetting(VerboseSetting, "Vprofile-sorted-by", "key", "Show metrics about sources and internal representations sorted by given column name", List("name", "path", "lines", "tokens", "tasty", "complexity"), "")
val VprofileDetails = IntSetting(VerboseSetting, "Vprofile-details", "Show metrics about sources and internal representations of the most complex methods", 0)
Expand Down Expand Up @@ -191,7 +190,6 @@ private sealed trait WarningSettings:
),
ChoiceWithHelp("unsafe-warn-patvars", "Deprecated alias for `patvars`"),
),
default = Nil
)
object WunusedHas:
def isChoiceSet(s: String)(using Context) = Wunused.value.pipe(us => us.contains(s))
Expand Down Expand Up @@ -225,7 +223,6 @@ private sealed trait WarningSettings:
WarningSetting,
"Wconf",
"patterns",
default = List(),
descr =
raw"""Configure compiler warnings.
|Syntax: -Wconf:<filters>:<action>,<filters>:<action>,...
Expand Down Expand Up @@ -287,7 +284,6 @@ private sealed trait WarningSettings:
ChoiceWithHelp("private-shadow", "Warn if a private field or class parameter shadows a superclass field"),
ChoiceWithHelp("type-parameter-shadow", "Warn when a type parameter shadows a type already in the scope"),
),
default = Nil
)

object WshadowHas:
Expand Down
Loading
Loading