Skip to content

Commit 997ca76

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

File tree

6 files changed

+53
-32
lines changed

6 files changed

+53
-32
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
367367
profiler.onPhase(phase):
368368
try units = phase.runOn(units)
369369
catch case _: InterruptedException => cancelInterrupted()
370-
if (ctx.settings.Vprint.value.containsPhase(phase))
370+
for (printAt <- ctx.settings.Vprint.userValue if printAt.containsPhase(phase))
371371
for (unit <- units)
372372
def printCtx(unit: CompilationUnit) = phase.printingContext(
373373
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
@@ -156,12 +156,15 @@ trait CliCommand:
156156
private def columnate(sb: StringBuilder, texts: List[List[(String, String)]])(using Context): Unit =
157157
import Highlighting.*
158158
val colors = Seq(Green(_), Yellow(_), Magenta(_), Cyan(_), Red(_))
159+
val bolds = Seq(GreenB(_), YellowB(_), MagentaB(_), CyanB(_), RedB(_))
159160
val nocolor = texts.length == 1
160161
def color(index: Int): String => Highlight = if nocolor then NoColor(_) else colors(index % colors.length)
162+
def colorB(index: Int): String => Highlight = if nocolor then NoColor(_) else bolds(index % colors.length)
161163
val maxCol = ctx.settings.pageWidth.value
162164
val field1 = maxField.min(texts.flatten.map(_._1.length).filter(_ < maxField).max) // widest field under maxField
163165
val field2 = if field1 + separation + maxField < maxCol then maxCol - field1 - separation else 0 // skinny window -> terminal wrap
164-
val separator = " " * separation
166+
val toMark = ctx.settings.XshowPhases.value.toSet
167+
def separator(name: String) = if toMark(name) then "->" + " " * (separation - 2) else " " * separation
165168
val EOL = "\n"
166169
def formatField1(text: String): String = if text.length <= field1 then text.padLeft(field1) else text + EOL + "".padLeft(field1)
167170
def formatField2(text: String): String =
@@ -170,15 +173,15 @@ trait CliCommand:
170173
else
171174
fld.lastIndexOf(" ", field2) match
172175
case -1 => List(fld)
173-
case i => val (prefix, rest) = fld.splitAt(i) ; prefix :: loopOverField2(rest.trim)
174-
text.split("\n").toList.flatMap(loopOverField2).filter(_.nonEmpty).mkString(EOL + "".padLeft(field1) + separator)
176+
case i => val (prefix, rest) = fld.splitAt(i); prefix :: loopOverField2(rest.trim)
177+
text.split("\n").toList.flatMap(loopOverField2).filter(_.nonEmpty).mkString(EOL + "".padLeft(field1) + separator("no-phase"))
175178
end formatField2
176179
def format(first: String, second: String, index: Int, colorPicker: Int => String => Highlight) =
177180
sb.append(colorPicker(index)(formatField1(first)).show)
178-
.append(separator)
181+
.append(colorPicker(index)(separator(first)).show)
179182
.append(formatField2(second))
180183
.append(EOL): Unit
181-
def fancy(first: String, second: String, index: Int) = format(first, second, index, color)
184+
def fancy(first: String, second: String, index: Int) = format(first, second, index, if toMark(first) then colorB else color)
182185
def plain(first: String, second: String) = format(first, second, 0, _ => NoColor(_))
183186

184187
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 & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,8 @@ private sealed trait PluginSettings:
144144
private sealed trait VerboseSettings:
145145
self: SettingGroup =>
146146
val Vhelp: Setting[Boolean] = BooleanSetting(VerboseSetting, "V", "Print a synopsis of verbose options.")
147-
val Vprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", aliases = List("-Xprint"))
148-
val XshowPhases: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vphases", "List compiler phases.", aliases = List("-Xshow-phases"))
149-
147+
val Vprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", default = "typer", aliases = List("-Xprint"))
148+
val XshowPhases: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vphases", "List compiler phases.", default = "none", aliases = List("-Xshow-phases"))
150149
val Vprofile: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vprofile", "Show metrics about sources and internal representations to estimate compile-time complexity.")
151150
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"), "")
152151
val VprofileDetails = IntSetting(VerboseSetting, "Vprofile-details", "Show metrics about sources and internal representations of the most complex methods", 0)

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

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

1616
object Settings:
1717

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

107109
val allFullNames: List[String] = s"$name" :: s"-$name" :: aliases
108110

111+
def isPresentIn(state: SettingsState): Boolean = state.wasChanged(idx)
112+
109113
def valueIn(state: SettingsState): T = state.value(idx).asInstanceOf[T]
110114

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

115121
def isDefaultIn(state: SettingsState): Boolean = valueIn(state) == default
116122

117-
def isMultivalue: Boolean = summon[ClassTag[T]] == ListTag
123+
def isMultivalue: Boolean = classTag[T] == ListTag
118124

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

121127
def legalChoices: String =
122128
choices match
@@ -132,7 +138,7 @@ object Settings:
132138
* Updates the value in state
133139
*
134140
* @param getValue it is crucial that this argument is passed by name, as [setOutput] have side effects.
135-
* @param argStringValue string value of currently proccessed argument that will be used to set deprecation replacement
141+
* @param argStringValue string value of currently processed argument that will be used to set deprecation replacement
136142
* @param args remaining arguments to process
137143
* @return new argumment state
138144
*/
@@ -168,11 +174,17 @@ object Settings:
168174

169175
def missingArg =
170176
val msg = s"missing argument for option $name"
171-
if ignoreInvalidArgs then state.warn(msg + ", the tag was ignored") else state.fail(msg)
177+
if ignoreInvalidArgs then state.warn(s"$msg, the tag was ignored") else state.fail(msg)
172178

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

177189
def setBoolean(argValue: String, args: List[String]) =
178190
if argValue.equalsIgnoreCase("true") || argValue.isEmpty then update(true, argValue, args)
@@ -201,11 +213,11 @@ object Settings:
201213
def setOutput(argValue: String, args: List[String]) =
202214
val path = Directory(argValue)
203215
val isJar = path.ext.isJar
204-
if (!isJar && !path.isDirectory) then
216+
if !isJar && !path.isDirectory then
205217
state.fail(s"'$argValue' does not exist or is not a directory or .jar file")
206218
else
207219
/* Side effect, do not change this method to evaluate eagerly */
208-
def output = if (isJar) JarArchive.create(path) else new PlainDirectory(path)
220+
def output = if isJar then JarArchive.create(path) else new PlainDirectory(path)
209221
update(output, argValue, args)
210222

211223
def setVersion(argValue: String, args: List[String]) =
@@ -226,22 +238,28 @@ object Settings:
226238
case _ => update(strings, argValue, args)
227239

228240
def doSet(argRest: String) =
229-
((summon[ClassTag[T]], args): @unchecked) match
230-
case (BooleanTag, _) =>
241+
classTag[T] match
242+
case BooleanTag =>
231243
if sstate.wasChanged(idx) && preferPrevious then ignoreValue(args)
232244
else setBoolean(argRest, args)
233-
case (OptionTag, _) =>
245+
case OptionTag =>
234246
update(Some(propertyClass.get.getConstructor().newInstance()), "", args)
235-
case (ct, args) =>
247+
case ct =>
236248
val argInArgRest = !argRest.isEmpty || legacyArgs
237-
val argAfterParam = !argInArgRest && args.nonEmpty && (ct == IntTag || !args.head.startsWith("-"))
249+
inline def argAfterParam = !argInArgRest && args.nonEmpty && (ct == IntTag || !args.head.startsWith("-"))
238250
if argInArgRest then
239251
doSetArg(argRest, args)
240252
else if argAfterParam then
241253
doSetArg(args.head, args.tail)
242-
else missingArg
254+
else if isEmptyDefault then
255+
missingArg
256+
else
257+
doSetArg(arg = null, args)
243258

244-
def doSetArg(arg: String, argsLeft: List[String]) = summon[ClassTag[T]] match
259+
def doSetArg(arg: String, argsLeft: List[String]) =
260+
classTag[T] match
261+
case ListTag if arg == null =>
262+
update(default, arg, argsLeft)
245263
case ListTag =>
246264
val strings = arg.split(",").toList
247265
appendList(strings, arg, argsLeft)
@@ -297,6 +315,7 @@ object Settings:
297315
object Setting:
298316
extension [T](setting: Setting[T])
299317
def value(using Context): T = setting.valueIn(ctx.settingsState)
318+
def userValue(using Context): Option[T] = setting.userValueIn(ctx.settingsState)
300319
def update(x: T)(using Context): SettingsState = setting.updateIn(ctx.settingsState, x)
301320
def isDefault(using Context): Boolean = setting.isDefaultIn(ctx.settingsState)
302321

@@ -427,7 +446,7 @@ object Settings:
427446
publish(Setting(category, prependName(name), descr, default, legacyArgs = legacyArgs, deprecation = deprecation))
428447

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

432451
end SettingGroup
433452
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)