Skip to content

Commit 2453572

Browse files
committed
-Vphases takes names to mark, -Vprint is typer
Distinguish whether a setting was "set" by the user.
1 parent b712447 commit 2453572

File tree

6 files changed

+53
-31
lines changed

6 files changed

+53
-31
lines changed

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
342342
profiler.onPhase(phase):
343343
try units = phase.runOn(units)
344344
catch case _: InterruptedException => cancelInterrupted()
345-
if (ctx.settings.Xprint.value.containsPhase(phase))
345+
for (printAt <- ctx.settings.Xprint.userValue if printAt.containsPhase(phase))
346346
for (unit <- units)
347347
def printCtx(unit: CompilationUnit) = phase.printingContext(
348348
ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))

compiler/src/dotty/tools/dotc/config/CliCommand.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,15 @@ trait CliCommand:
158158
private def columnate(sb: StringBuilder, texts: List[List[(String, String)]])(using Context): Unit =
159159
import Highlighting.*
160160
val colors = Seq(Green(_), Yellow(_), Magenta(_), Cyan(_), Red(_))
161+
val bolds = Seq(GreenB(_), YellowB(_), MagentaB(_), CyanB(_), RedB(_))
161162
val nocolor = texts.length == 1
162163
def color(index: Int): String => Highlight = if nocolor then NoColor(_) else colors(index % colors.length)
164+
def colorB(index: Int): String => Highlight = if nocolor then NoColor(_) else bolds(index % colors.length)
163165
val maxCol = ctx.settings.pageWidth.value
164166
val field1 = maxField.min(texts.flatten.map(_._1.length).filter(_ < maxField).max) // widest field under maxField
165167
val field2 = if field1 + separation + maxField < maxCol then maxCol - field1 - separation else 0 // skinny window -> terminal wrap
166-
val separator = " " * separation
168+
val toMark = ctx.settings.XshowPhases.value.toSet
169+
def separator(name: String) = if toMark(name) then "->" + " " * (separation - 2) else " " * separation
167170
val EOL = "\n"
168171
def formatField1(text: String): String = if text.length <= field1 then text.padLeft(field1) else text + EOL + "".padLeft(field1)
169172
def formatField2(text: String): String =
@@ -172,15 +175,15 @@ trait CliCommand:
172175
else
173176
fld.lastIndexOf(" ", field2) match
174177
case -1 => List(fld)
175-
case i => val (prefix, rest) = fld.splitAt(i) ; prefix :: loopOverField2(rest.trim)
176-
text.split("\n").toList.flatMap(loopOverField2).filter(_.nonEmpty).mkString(EOL + "".padLeft(field1) + separator)
178+
case i => val (prefix, rest) = fld.splitAt(i); prefix :: loopOverField2(rest.trim)
179+
text.split("\n").toList.flatMap(loopOverField2).filter(_.nonEmpty).mkString(EOL + "".padLeft(field1) + separator("no-phase"))
177180
end formatField2
178181
def format(first: String, second: String, index: Int, colorPicker: Int => String => Highlight) =
179182
sb.append(colorPicker(index)(formatField1(first)).show)
180-
.append(separator)
183+
.append(colorPicker(index)(separator(first)).show)
181184
.append(formatField2(second))
182185
.append(EOL): Unit
183-
def fancy(first: String, second: String, index: Int) = format(first, second, index, color)
186+
def fancy(first: String, second: String, index: Int) = format(first, second, index, if toMark(first) then colorB else color)
184187
def plain(first: String, second: String) = format(first, second, 0, _ => NoColor(_))
185188

186189
if heading1.nonEmpty then

compiler/src/dotty/tools/dotc/config/CompilerCommand.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ abstract class CompilerCommand extends CliCommand:
1818
else if (settings.Xhelp.value) xusageMessage
1919
else if (settings.Yhelp.value) yusageMessage
2020
else if (settings.showPlugins.value) ctx.base.pluginDescriptions
21-
else if (settings.XshowPhases.value) phasesMessage
21+
else if settings.XshowPhases.isPresentIn(summon[SettingsState]) then phasesMessage
2222
else ""
2323

2424
final def isHelpFlag(using settings: ConcreteSettings)(using SettingsState): Boolean =
2525
import settings.*
26-
val flags = Set(help, Vhelp, Whelp, Xhelp, Yhelp, showPlugins, XshowPhases)
27-
flags.exists(_.value) || allSettings.exists(isHelping)
26+
val flags = Set(help, Vhelp, Whelp, Xhelp, Yhelp, showPlugins)
27+
flags.exists(_.value) || XshowPhases.isPresentIn(summon[SettingsState]) || allSettings.exists(isHelping)

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ private sealed trait PluginSettings:
142142
private sealed trait VerboseSettings:
143143
self: SettingGroup =>
144144
val Vhelp: Setting[Boolean] = BooleanSetting(VerboseSetting, "V", "Print a synopsis of verbose options.")
145-
val Xprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", aliases = List("-Xprint"))
146-
val XshowPhases: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vphases", "List compiler phases.", aliases = List("-Xshow-phases"))
145+
val Xprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", default = "typer", aliases = List("-Xprint"))
146+
val XshowPhases: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vphases", "List compiler phases.", default = "none", aliases = List("-Xshow-phases"))
147147

148148
val Vprofile: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vprofile", "Show metrics about sources and internal representations to estimate compile-time complexity.")
149149
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"), "")

compiler/src/dotty/tools/dotc/config/Settings.scala

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import dotty.tools.dotc.config.Settings.Setting.ChoiceWithHelp
1717

1818
object Settings:
1919

20+
private inline def classTag[T](using ctag: ClassTag[T]): ClassTag[T] = ctag
21+
2022
val BooleanTag: ClassTag[Boolean] = ClassTag.Boolean
2123
val IntTag: ClassTag[Int] = ClassTag.Int
2224
val StringTag: ClassTag[String] = ClassTag(classOf[String])
@@ -104,21 +106,25 @@ object Settings:
104106
assert(legacyArgs || !choices.exists(_.contains("")), s"Empty string is not supported as a choice for setting $name")
105107
// Without the following assertion, it would be easy to mistakenly try to pass a file to a setting that ignores invalid args.
106108
// Example: -opt Main.scala would be interpreted as -opt:Main.scala, and the source file would be ignored.
107-
assert(!(summon[ClassTag[T]] == ListTag && ignoreInvalidArgs), s"Ignoring invalid args is not supported for multivalue settings: $name")
109+
assert(!(classTag[T] == ListTag && ignoreInvalidArgs), s"Ignoring invalid args is not supported for multivalue settings: $name")
108110

109111
val allFullNames: List[String] = s"$name" :: s"-$name" :: aliases
110112

113+
def isPresentIn(state: SettingsState): Boolean = state.wasChanged(idx)
114+
111115
def valueIn(state: SettingsState): T = state.value(idx).asInstanceOf[T]
112116

117+
def userValueIn(state: SettingsState): Option[T] = if isPresentIn(state) then Some(valueIn(state)) else None
118+
113119
def updateIn(state: SettingsState, x: Any): SettingsState = x match
114120
case _: T => state.update(idx, x)
115-
case _ => throw IllegalArgumentException(s"found: $x of type ${x.getClass.getName}, required: ${summon[ClassTag[T]]}")
121+
case _ => throw IllegalArgumentException(s"found: $x of type ${x.getClass.getName}, required: ${classTag[T]}")
116122

117123
def isDefaultIn(state: SettingsState): Boolean = valueIn(state) == default
118124

119-
def isMultivalue: Boolean = summon[ClassTag[T]] == ListTag
125+
def isMultivalue: Boolean = classTag[T] == ListTag
120126

121-
def acceptsNoArg: Boolean = summon[ClassTag[T]] == BooleanTag || summon[ClassTag[T]] == OptionTag || choices.exists(_.contains(""))
127+
def acceptsNoArg: Boolean = classTag[T] == BooleanTag || classTag[T] == OptionTag || choices.exists(_.contains(""))
122128

123129
def legalChoices: String =
124130
choices match
@@ -134,7 +140,7 @@ object Settings:
134140
* Updates the value in state
135141
*
136142
* @param getValue it is crucial that this argument is passed by name, as [setOutput] have side effects.
137-
* @param argStringValue string value of currently proccessed argument that will be used to set deprecation replacement
143+
* @param argStringValue string value of currently processed argument that will be used to set deprecation replacement
138144
* @param args remaining arguments to process
139145
* @return new argumment state
140146
*/
@@ -170,11 +176,17 @@ object Settings:
170176

171177
def missingArg =
172178
val msg = s"missing argument for option $name"
173-
if ignoreInvalidArgs then state.warn(msg + ", the tag was ignored") else state.fail(msg)
179+
if ignoreInvalidArgs then state.warn(s"$msg, the tag was ignored") else state.fail(msg)
174180

175181
def invalidChoices(invalid: List[String]) =
176182
val msg = s"invalid choice(s) for $name: ${invalid.mkString(",")}"
177-
if ignoreInvalidArgs then state.warn(msg + ", the tag was ignored") else state.fail(msg)
183+
if ignoreInvalidArgs then state.warn(s"$msg, the tag was ignored") else state.fail(msg)
184+
185+
def isEmptyDefault = default == null.asInstanceOf[T] || classTag[T].match
186+
case ListTag => default.asInstanceOf[List[?]].isEmpty
187+
case StringTag => default.asInstanceOf[String].isEmpty
188+
case OptionTag => default.asInstanceOf[Option[?]].isEmpty
189+
case _ => false
178190

179191
def setBoolean(argValue: String, args: List[String]) =
180192
if argValue.equalsIgnoreCase("true") || argValue.isEmpty then update(true, argValue, args)
@@ -203,11 +215,11 @@ object Settings:
203215
def setOutput(argValue: String, args: List[String]) =
204216
val path = Directory(argValue)
205217
val isJar = path.ext.isJar
206-
if (!isJar && !path.isDirectory) then
218+
if !isJar && !path.isDirectory then
207219
state.fail(s"'$argValue' does not exist or is not a directory or .jar file")
208220
else
209221
/* Side effect, do not change this method to evaluate eagerly */
210-
def output = if (isJar) JarArchive.create(path) else new PlainDirectory(path)
222+
def output = if isJar then JarArchive.create(path) else new PlainDirectory(path)
211223
update(output, argValue, args)
212224

213225
def setVersion(argValue: String, args: List[String]) =
@@ -228,22 +240,28 @@ object Settings:
228240
case _ => update(strings, argValue, args)
229241

230242
def doSet(argRest: String) =
231-
((summon[ClassTag[T]], args): @unchecked) match
232-
case (BooleanTag, _) =>
243+
classTag[T] match
244+
case BooleanTag =>
233245
if sstate.wasChanged(idx) && preferPrevious then ignoreValue(args)
234246
else setBoolean(argRest, args)
235-
case (OptionTag, _) =>
247+
case OptionTag =>
236248
update(Some(propertyClass.get.getConstructor().newInstance()), "", args)
237-
case (ct, args) =>
249+
case ct =>
238250
val argInArgRest = !argRest.isEmpty || legacyArgs
239-
val argAfterParam = !argInArgRest && args.nonEmpty && (ct == IntTag || !args.head.startsWith("-"))
251+
inline def argAfterParam = !argInArgRest && args.nonEmpty && (ct == IntTag || !args.head.startsWith("-"))
240252
if argInArgRest then
241253
doSetArg(argRest, args)
242254
else if argAfterParam then
243255
doSetArg(args.head, args.tail)
244-
else missingArg
256+
else if isEmptyDefault then
257+
missingArg
258+
else
259+
doSetArg(arg = null, args)
245260

246-
def doSetArg(arg: String, argsLeft: List[String]) = summon[ClassTag[T]] match
261+
def doSetArg(arg: String, argsLeft: List[String]) =
262+
classTag[T] match
263+
case ListTag if arg == null =>
264+
update(default, arg, argsLeft)
247265
case ListTag =>
248266
val strings = arg.split(",").toList
249267
appendList(strings, arg, argsLeft)
@@ -299,6 +317,7 @@ object Settings:
299317
object Setting:
300318
extension [T](setting: Setting[T])
301319
def value(using Context): T = setting.valueIn(ctx.settingsState)
320+
def userValue(using Context): Option[T] = setting.userValueIn(ctx.settingsState)
302321
def update(x: T)(using Context): SettingsState = setting.updateIn(ctx.settingsState, x)
303322
def isDefault(using Context): Boolean = setting.isDefaultIn(ctx.settingsState)
304323

@@ -429,7 +448,7 @@ object Settings:
429448
publish(Setting(category, prependName(name), descr, default, legacyArgs = legacyArgs, deprecation = deprecation))
430449

431450
def OptionSetting[T: ClassTag](category: SettingCategory, name: String, descr: String, aliases: List[String] = Nil, deprecation: Option[Deprecation] = None): Setting[Option[T]] =
432-
publish(Setting(category, prependName(name), descr, None, propertyClass = Some(summon[ClassTag[T]].runtimeClass), aliases = aliases, deprecation = deprecation))
451+
publish(Setting(category, prependName(name), descr, None, propertyClass = Some(classTag[T].runtimeClass), aliases = aliases, deprecation = deprecation))
433452

434453
end SettingGroup
435454
end Settings

compiler/src/dotty/tools/dotc/core/Decorators.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,13 @@ object Decorators {
251251
* a given phase. See [[config.CompilerCommand#explainAdvanced]] for the
252252
* exact meaning of "contains" here.
253253
*/
254-
extension (names: List[String])
254+
extension (names: List[String])
255255
def containsPhase(phase: Phase): Boolean =
256256
names.nonEmpty && {
257257
phase match {
258-
case phase: MegaPhase => phase.miniPhases.exists(x => names.containsPhase(x))
258+
case phase: MegaPhase => phase.miniPhases.exists(names.containsPhase)
259259
case _ =>
260-
names exists { name =>
260+
names.exists { name =>
261261
name == "all" || {
262262
val strippedName = name.stripSuffix("+")
263263
val logNextPhase = name != strippedName

0 commit comments

Comments
 (0)