@@ -17,6 +17,8 @@ import dotty.tools.dotc.config.Settings.Setting.ChoiceWithHelp
1717
1818object 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
435454end Settings
0 commit comments