@@ -17,6 +17,8 @@ import dotty.tools.dotc.config.Settings.Setting.ChoiceWithHelp
17
17
18
18
object Settings :
19
19
20
+ private inline def classTag [T ](using ctag : ClassTag [T ]): ClassTag [T ] = ctag
21
+
20
22
val BooleanTag : ClassTag [Boolean ] = ClassTag .Boolean
21
23
val IntTag : ClassTag [Int ] = ClassTag .Int
22
24
val StringTag : ClassTag [String ] = ClassTag (classOf [String ])
@@ -93,21 +95,25 @@ object Settings:
93
95
assert(legacyArgs || ! choices.exists(_.contains(" " )), s " Empty string is not supported as a choice for setting $name" )
94
96
// Without the following assertion, it would be easy to mistakenly try to pass a file to a setting that ignores invalid args.
95
97
// Example: -opt Main.scala would be interpreted as -opt:Main.scala, and the source file would be ignored.
96
- assert(! (summon[ ClassTag [ T ] ] == ListTag && ignoreInvalidArgs), s " Ignoring invalid args is not supported for multivalue settings: $name" )
98
+ assert(! (classTag[ T ] == ListTag && ignoreInvalidArgs), s " Ignoring invalid args is not supported for multivalue settings: $name" )
97
99
98
100
val allFullNames : List [String ] = s " $name" :: s " - $name" :: aliases
99
101
102
+ def isPresentIn (state : SettingsState ): Boolean = state.wasChanged(idx)
103
+
100
104
def valueIn (state : SettingsState ): T = state.value(idx).asInstanceOf [T ]
101
105
106
+ def userValueIn (state : SettingsState ): Option [T ] = if isPresentIn(state) then Some (valueIn(state)) else None
107
+
102
108
def updateIn (state : SettingsState , x : Any ): SettingsState = x match
103
109
case _ : T => state.update(idx, x)
104
- case _ => throw IllegalArgumentException (s " found: $x of type ${x.getClass.getName}, required: ${summon[ ClassTag [ T ] ]}" )
110
+ case _ => throw IllegalArgumentException (s " found: $x of type ${x.getClass.getName}, required: ${classTag[ T ]}" )
105
111
106
112
def isDefaultIn (state : SettingsState ): Boolean = valueIn(state) == default
107
113
108
- def isMultivalue : Boolean = summon[ ClassTag [ T ] ] == ListTag
114
+ def isMultivalue : Boolean = classTag[ T ] == ListTag
109
115
110
- def acceptsNoArg : Boolean = summon[ ClassTag [ T ]] == BooleanTag || summon[ ClassTag [ T ] ] == OptionTag || choices.exists(_.contains(" " ))
116
+ def acceptsNoArg : Boolean = classTag[ T ] == BooleanTag || classTag[ T ] == OptionTag || choices.exists(_.contains(" " ))
111
117
112
118
def legalChoices : String =
113
119
choices match
@@ -123,7 +129,7 @@ object Settings:
123
129
* Updates the value in state
124
130
*
125
131
* @param getValue it is crucial that this argument is passed by name, as [setOutput] have side effects.
126
- * @param argStringValue string value of currently proccessed argument that will be used to set deprecation replacement
132
+ * @param argStringValue string value of currently processed argument that will be used to set deprecation replacement
127
133
* @param args remaining arguments to process
128
134
* @return new argumment state
129
135
*/
@@ -159,11 +165,17 @@ object Settings:
159
165
160
166
def missingArg =
161
167
val msg = s " missing argument for option $name"
162
- if ignoreInvalidArgs then state.warn(msg + " , the tag was ignored" ) else state.fail(msg)
168
+ if ignoreInvalidArgs then state.warn(s " $msg , the tag was ignored " ) else state.fail(msg)
163
169
164
170
def invalidChoices (invalid : List [String ]) =
165
171
val msg = s " invalid choice(s) for $name: ${invalid.mkString(" ," )}"
166
- if ignoreInvalidArgs then state.warn(msg + " , the tag was ignored" ) else state.fail(msg)
172
+ if ignoreInvalidArgs then state.warn(s " $msg, the tag was ignored " ) else state.fail(msg)
173
+
174
+ def isEmptyDefault = default == null .asInstanceOf [T ] || classTag[T ].match
175
+ case ListTag => default.asInstanceOf [List [? ]].isEmpty
176
+ case StringTag => default.asInstanceOf [String ].isEmpty
177
+ case OptionTag => default.asInstanceOf [Option [? ]].isEmpty
178
+ case _ => false
167
179
168
180
def setBoolean (argValue : String , args : List [String ]) =
169
181
if argValue.equalsIgnoreCase(" true" ) || argValue.isEmpty then update(true , argValue, args)
@@ -192,11 +204,11 @@ object Settings:
192
204
def setOutput (argValue : String , args : List [String ]) =
193
205
val path = Directory (argValue)
194
206
val isJar = path.ext.isJar
195
- if ( ! isJar && ! path.isDirectory) then
207
+ if ! isJar && ! path.isDirectory then
196
208
state.fail(s " ' $argValue' does not exist or is not a directory or .jar file " )
197
209
else
198
210
/* Side effect, do not change this method to evaluate eagerly */
199
- def output = if ( isJar) JarArchive .create(path) else new PlainDirectory (path)
211
+ def output = if isJar then JarArchive .create(path) else new PlainDirectory (path)
200
212
update(output, argValue, args)
201
213
202
214
def setVersion (argValue : String , args : List [String ]) =
@@ -212,22 +224,28 @@ object Settings:
212
224
case _ => update(strings, argValue, args)
213
225
214
226
def doSet (argRest : String ) =
215
- ((summon[ ClassTag [ T ]], args) : @ unchecked) match
216
- case ( BooleanTag , _) =>
227
+ classTag[ T ] match
228
+ case BooleanTag =>
217
229
if sstate.wasChanged(idx) && preferPrevious then ignoreValue(args)
218
230
else setBoolean(argRest, args)
219
- case ( OptionTag , _) =>
231
+ case OptionTag =>
220
232
update(Some (propertyClass.get.getConstructor().newInstance()), " " , args)
221
- case (ct, args) =>
233
+ case ct =>
222
234
val argInArgRest = ! argRest.isEmpty || legacyArgs
223
- val argAfterParam = ! argInArgRest && args.nonEmpty && (ct == IntTag || ! args.head.startsWith(" -" ))
235
+ inline def argAfterParam = ! argInArgRest && args.nonEmpty && (ct == IntTag || ! args.head.startsWith(" -" ))
224
236
if argInArgRest then
225
237
doSetArg(argRest, args)
226
238
else if argAfterParam then
227
239
doSetArg(args.head, args.tail)
228
- else missingArg
240
+ else if isEmptyDefault then
241
+ missingArg
242
+ else
243
+ doSetArg(arg = null , args)
229
244
230
- def doSetArg (arg : String , argsLeft : List [String ]) = summon[ClassTag [T ]] match
245
+ def doSetArg (arg : String , argsLeft : List [String ]) =
246
+ classTag[T ] match
247
+ case ListTag if arg == null =>
248
+ update(List (default), arg, argsLeft)
231
249
case ListTag =>
232
250
val strings = arg.split(" ," ).toList
233
251
appendList(strings, arg, argsLeft)
@@ -283,6 +301,7 @@ object Settings:
283
301
object Setting :
284
302
extension [T ](setting : Setting [T ])
285
303
def value (using Context ): T = setting.valueIn(ctx.settingsState)
304
+ def userValue (using Context ): Option [T ] = setting.userValueIn(ctx.settingsState)
286
305
def update (x : T )(using Context ): SettingsState = setting.updateIn(ctx.settingsState, x)
287
306
def isDefault (using Context ): Boolean = setting.isDefaultIn(ctx.settingsState)
288
307
@@ -412,7 +431,7 @@ object Settings:
412
431
publish(Setting (category, prependName(name), descr, default, legacyArgs = legacyArgs, deprecation = deprecation))
413
432
414
433
def OptionSetting [T : ClassTag ](category : SettingCategory , name : String , descr : String , aliases : List [String ] = Nil , deprecation : Option [Deprecation ] = None ): Setting [Option [T ]] =
415
- publish(Setting (category, prependName(name), descr, None , propertyClass = Some (summon[ ClassTag [ T ] ].runtimeClass), aliases = aliases, deprecation = deprecation))
434
+ publish(Setting (category, prependName(name), descr, None , propertyClass = Some (classTag[ T ].runtimeClass), aliases = aliases, deprecation = deprecation))
416
435
417
436
end SettingGroup
418
437
end Settings
0 commit comments