@@ -1132,7 +1132,7 @@ trait Namers extends MethodSynthesis {
1132
1132
}
1133
1133
}
1134
1134
1135
- addDefaultGetters(meth, vparamss, tparams, overriddenSymbol(methResTp))
1135
+ addDefaultGetters(meth, ddef, vparamss, tparams, overriddenSymbol(methResTp))
1136
1136
1137
1137
// fast track macros, i.e. macros defined inside the compiler, are hardcoded
1138
1138
// hence we make use of that and let them have whatever right-hand side they need
@@ -1174,7 +1174,12 @@ trait Namers extends MethodSynthesis {
1174
1174
* typechecked, the corresponding param would not yet have the "defaultparam"
1175
1175
* flag.
1176
1176
*/
1177
- private def addDefaultGetters (meth : Symbol , vparamss : List [List [ValDef ]], tparams : List [TypeDef ], overriddenSymbol : => Symbol ) {
1177
+ private def addDefaultGetters (meth : Symbol , ddef : DefDef , vparamss : List [List [ValDef ]], tparams : List [TypeDef ], overriddenSymbol : => Symbol ) {
1178
+ val DefDef (_, _, rtparams0, rvparamss0, _, _) = resetLocalAttrs(ddef.duplicate)
1179
+ // having defs here is important to make sure that there's no sneaky tree sharing
1180
+ // in methods with multiple default parameters
1181
+ def rtparams = rtparams0.map(_.duplicate)
1182
+ def rvparamss = rvparamss0.map(_.map(_.duplicate))
1178
1183
val methOwner = meth.owner
1179
1184
val isConstr = meth.isConstructor
1180
1185
val overridden = if (isConstr || ! methOwner.isClass) NoSymbol else overriddenSymbol
@@ -1206,23 +1211,36 @@ trait Namers extends MethodSynthesis {
1206
1211
//
1207
1212
vparamss.foldLeft(Nil : List [List [ValDef ]]) { (previous, vparams) =>
1208
1213
assert(! overrides || vparams.length == baseParamss.head.length, " " + meth.fullName + " , " + overridden.fullName)
1214
+ val rvparams = rvparamss(previous.length)
1209
1215
var baseParams = if (overrides) baseParamss.head else Nil
1210
- for ( vparam <- vparams) {
1216
+ map2(vparams, rvparams)(( vparam, rvparam) => {
1211
1217
val sym = vparam.symbol
1212
1218
// true if the corresponding parameter of the base class has a default argument
1213
1219
val baseHasDefault = overrides && baseParams.head.hasDefault
1214
1220
if (sym.hasDefault) {
1215
- // generate a default getter for that argument
1221
+ // Create a "default getter", i.e. a DefDef that will calculate vparam.rhs
1222
+ // for those who are going to call meth without providing an argument corresponding to vparam.
1223
+ // After the getter is created, a corresponding synthetic symbol is created and entered into the parent namer.
1224
+ //
1225
+ // In the ideal world, this DefDef would be a simple one-liner that just returns vparam.rhs,
1226
+ // but in scalac things are complicated in two different ways.
1227
+ //
1228
+ // 1) Because the underlying language is quite sophisticated, we must allow for those sophistications in our getter.
1229
+ // Namely: a) our getter has to copy type parameters from the associated method (or the associated class
1230
+ // if meth is a constructor), because vparam.rhs might refer to one of them, b) our getter has to copy
1231
+ // preceding value parameter lists from the associated method, because again vparam.rhs might refer to one of them.
1232
+ //
1233
+ // 2) Because we have already assigned symbols to type and value parameters that we have to copy, we must jump through
1234
+ // hoops in order to destroy them and allow subsequent naming create new symbols for our getter. Previously this
1235
+ // was done in an overly brutal way akin to resetAllAttrs, but now we utilize a resetLocalAttrs-based approach.
1236
+ // Still far from ideal, but at least enables things like run/macro-default-params that were previously impossible.
1237
+
1216
1238
val oflag = if (baseHasDefault) OVERRIDE else 0
1217
1239
val name = nme.defaultGetterName(meth.name, posCounter)
1218
1240
1219
- // Create trees for the defaultGetter. Uses tools from Unapplies.scala
1220
- var deftParams = tparams map copyUntyped[TypeDef ]
1221
- val defvParamss = mmap(previous) { p =>
1222
- // in the default getter, remove the default parameter
1223
- val p1 = atPos(p.pos.focus) { ValDef (p.mods &~ DEFAULTPARAM , p.name, p.tpt.duplicate, EmptyTree ) }
1224
- UnTyper .traverse(p1)
1225
- p1
1241
+ var defTparams = rtparams
1242
+ val defVparamss = mmap(rvparamss.take(previous.length)){ rvp =>
1243
+ copyValDef(rvp)(mods = rvp.mods &~ DEFAULTPARAM , rhs = EmptyTree )
1226
1244
}
1227
1245
1228
1246
val parentNamer = if (isConstr) {
@@ -1244,7 +1262,8 @@ trait Namers extends MethodSynthesis {
1244
1262
return // fix #3649 (prevent crash in erroneous source code)
1245
1263
}
1246
1264
}
1247
- deftParams = cdef.tparams map copyUntypedInvariant
1265
+ val ClassDef (_, _, rtparams, _) = resetLocalAttrs(cdef.duplicate)
1266
+ defTparams = rtparams.map(rt => copyTypeDef(rt)(mods = rt.mods &~ (COVARIANT | CONTRAVARIANT )))
1248
1267
nmr
1249
1268
}
1250
1269
else ownerNamer getOrElse {
@@ -1255,23 +1274,30 @@ trait Namers extends MethodSynthesis {
1255
1274
nmr
1256
1275
}
1257
1276
1258
- // If the parameter type mentions any type parameter of the method, let the compiler infer the
1259
- // return type of the default getter => allow "def foo[T](x: T = 1)" to compile.
1260
- // This is better than always using Wildcard for inferring the result type, for example in
1261
- // def f(i: Int, m: Int => Int = identity _) = m(i)
1262
- // if we use Wildcard as expected, we get "Nothing => Nothing", and the default is not usable.
1263
- val names = deftParams map { case TypeDef (_, name, _, _) => name }
1264
- val subst = new TypeTreeSubstituter (names contains _)
1265
-
1266
- val defTpt = subst(copyUntyped(vparam.tpt match {
1267
- // default getter for by-name params
1268
- case AppliedTypeTree (_, List (arg)) if sym.hasFlag(BYNAMEPARAM ) => arg
1269
- case t => t
1270
- }))
1271
- val defRhs = copyUntyped(vparam.rhs)
1277
+ val defTpt =
1278
+ // don't mess with tpt's of case copy default getters, because assigning something other than TypeTree()
1279
+ // will break the carefully orchestrated naming/typing logic that involves enterCopyMethod and caseClassCopyMeth
1280
+ if (meth.isCaseCopy) TypeTree ()
1281
+ else {
1282
+ // If the parameter type mentions any type parameter of the method, let the compiler infer the
1283
+ // return type of the default getter => allow "def foo[T](x: T = 1)" to compile.
1284
+ // This is better than always using Wildcard for inferring the result type, for example in
1285
+ // def f(i: Int, m: Int => Int = identity _) = m(i)
1286
+ // if we use Wildcard as expected, we get "Nothing => Nothing", and the default is not usable.
1287
+ // TODO: this is a very brittle approach; I sincerely hope that Denys's research into hygiene
1288
+ // will open the doors to a much better way of doing this kind of stuff
1289
+ val tparamNames = defTparams map { case TypeDef (_, name, _, _) => name }
1290
+ val eraseAllMentionsOfTparams = new TypeTreeSubstituter (tparamNames contains _)
1291
+ eraseAllMentionsOfTparams(rvparam.tpt match {
1292
+ // default getter for by-name params
1293
+ case AppliedTypeTree (_, List (arg)) if sym.hasFlag(BYNAMEPARAM ) => arg
1294
+ case t => t
1295
+ })
1296
+ }
1297
+ val defRhs = rvparam.rhs
1272
1298
1273
1299
val defaultTree = atPos(vparam.pos.focus) {
1274
- DefDef (Modifiers (paramFlagsToDefaultGetter(meth.flags)) | oflag, name, deftParams, defvParamss , defTpt, defRhs)
1300
+ DefDef (Modifiers (paramFlagsToDefaultGetter(meth.flags)) | oflag, name, defTparams, defVparamss , defTpt, defRhs)
1275
1301
}
1276
1302
if (! isConstr)
1277
1303
methOwner.resetFlag(INTERFACE ) // there's a concrete member now
@@ -1286,7 +1312,7 @@ trait Namers extends MethodSynthesis {
1286
1312
}
1287
1313
posCounter += 1
1288
1314
if (overrides) baseParams = baseParams.tail
1289
- }
1315
+ })
1290
1316
if (overrides) baseParamss = baseParamss.tail
1291
1317
previous :+ vparams
1292
1318
}
0 commit comments