@@ -226,29 +226,40 @@ object desugar {
226
226
private def defDef (meth : DefDef , isPrimaryConstructor : Boolean = false )(using Context ): Tree =
227
227
addDefaultGetters(elimContextBounds(meth, isPrimaryConstructor))
228
228
229
+ /** Drop context bounds in given TypeDef, replacing them with evidence ValDefs that
230
+ * get added to a buffer.
231
+ * @param tdef The given TypeDef
232
+ * @param evidenceBuf The buffer to which evidence gets added. This buffer
233
+ * is shared between desugarings of different type parameters
234
+ * of the same method.
235
+ * @param evidenceFlags The flags to use for evidence definitions
236
+ * @param freshName A function to generate fresh names for evidence definitions
237
+ * @param allParams If `tdef` is a type paramter, all parameters of the owning method,
238
+ * otherwise the empty list.
239
+ */
229
240
private def desugarContextBounds (
230
241
tdef : TypeDef ,
231
242
evidenceBuf : ListBuffer [ValDef ],
232
- flags : FlagSet ,
243
+ evidenceFlags : FlagSet ,
233
244
freshName : untpd.Tree => TermName ,
234
245
allParamss : List [ParamClause ])(using Context ): TypeDef =
235
246
236
247
val evidenceNames = ListBuffer [TermName ]()
237
248
238
249
def desugarRhs (rhs : Tree ): Tree = rhs match
239
250
case ContextBounds (tbounds, cxbounds) =>
240
- val isMember = flags .isAllOf(DeferredGivenFlags )
251
+ val isMember = evidenceFlags .isAllOf(DeferredGivenFlags )
241
252
for bound <- cxbounds do
242
253
val evidenceName = bound match
243
254
case ContextBoundTypeTree (_, _, ownName) if ! ownName.isEmpty =>
244
- ownName
255
+ ownName // if there is an explicitly given name, use it.
245
256
case _ if Config .nameSingleContextBounds && ! isMember
246
257
&& cxbounds.tail.isEmpty && Feature .enabled(Feature .modularity) =>
247
258
tdef.name.toTermName
248
259
case _ =>
249
260
freshName(bound)
250
261
evidenceNames += evidenceName
251
- val evidenceParam = ValDef (evidenceName, bound, EmptyTree ).withFlags(flags )
262
+ val evidenceParam = ValDef (evidenceName, bound, EmptyTree ).withFlags(evidenceFlags )
252
263
evidenceParam.pushAttachment(ContextBoundParam , ())
253
264
evidenceBuf += evidenceParam
254
265
tbounds
@@ -258,9 +269,13 @@ object desugar {
258
269
rhs
259
270
260
271
val tdef1 = cpy.TypeDef (tdef)(rhs = desugarRhs(tdef.rhs))
272
+ // Under x.modularity, if there was a context bound, and `tdef`s name as a term name is
273
+ // neither a name of an existing parameter nor a name of generated evidence for
274
+ // the same method, add a WitnessAnnotation with all generated evidence names to `tdef`.
275
+ // This means a context bound proxy will be created later.
261
276
if Feature .enabled(Feature .modularity)
262
277
&& evidenceNames.nonEmpty
263
- && ! evidenceNames.contains( tdef.name.toTermName)
278
+ && ! evidenceBuf.exists(_.name == tdef.name.toTermName)
264
279
&& ! allParamss.nestedExists(_.name == tdef.name.toTermName)
265
280
then
266
281
tdef1.withAddedAnnotation:
@@ -272,6 +287,7 @@ object desugar {
272
287
private def elimContextBounds (meth : DefDef , isPrimaryConstructor : Boolean )(using Context ): DefDef =
273
288
val DefDef (_, paramss, tpt, rhs) = meth
274
289
val evidenceParamBuf = ListBuffer [ValDef ]()
290
+
275
291
var seenContextBounds : Int = 0
276
292
def freshName (unused : Tree ) =
277
293
seenContextBounds += 1 // Start at 1 like FreshNameCreator.
@@ -331,9 +347,9 @@ object desugar {
331
347
332
348
def getterParamss (n : Int ): List [ParamClause ] =
333
349
mapParamss(takeUpTo(paramssNoRHS, n)) {
334
- tparam => dropContextBounds(toDefParam (tparam, KeepAnnotations .All ))
350
+ tparam => dropContextBounds(toMethParam (tparam, KeepAnnotations .All ))
335
351
} {
336
- vparam => toDefParam (vparam, KeepAnnotations .All , keepDefault = false )
352
+ vparam => toMethParam (vparam, KeepAnnotations .All , keepDefault = false )
337
353
}
338
354
339
355
def defaultGetters (paramss : List [ParamClause ], n : Int ): List [DefDef ] = paramss match
@@ -428,32 +444,30 @@ object desugar {
428
444
* The position of the added parameters is determined as follows:
429
445
*
430
446
* - If there is an existing parameter list that refers to one of the added
431
- * parameters in one of its parameter types, add the new parameters
432
- * in front of the first such parameter list.
433
- * - Otherwise, if the last parameter list consists implicit or using parameters,
447
+ * parameters or their future context bound proxies in one of its parameter
448
+ * types, add the new parameters in front of the first such parameter list.
449
+ * - Otherwise, if the last parameter list consists of implicit or using parameters,
434
450
* join the new parameters in front of this parameter list, creating one
435
- * parameter list (this is equilavent to Scala 2's scheme).
451
+ * parameter list (this is equivalent to Scala 2's scheme).
436
452
* - Otherwise, add the new parameter list at the end as a separate parameter clause.
437
453
*/
438
454
private def addEvidenceParams (meth : DefDef , params : List [ValDef ])(using Context ): DefDef =
439
455
if params.isEmpty then return meth
440
456
441
- var boundNames = params.map(_.name).toSet
457
+ var boundNames = params.map(_.name).toSet // all evidence parameter + context bound proxy names
442
458
for mparams <- meth.paramss; mparam <- mparams do
443
459
mparam match
444
460
case tparam : TypeDef if tparam.mods.annotations.exists(WitnessNamesAnnot .unapply(_).isDefined) =>
445
461
boundNames += tparam.name.toTermName
446
462
case _ =>
447
463
448
- // println(i"add ev params ${meth.name}, ${boundNames.toList}")
449
-
450
- def references (vdef : ValDef ): Boolean =
464
+ def referencesBoundName (vdef : ValDef ): Boolean =
451
465
vdef.tpt.existsSubTree:
452
466
case Ident (name : TermName ) => boundNames.contains(name)
453
467
case _ => false
454
468
455
469
def recur (mparamss : List [ParamClause ]): List [ParamClause ] = mparamss match
456
- case ValDefs (mparams) :: _ if mparams.exists(references ) =>
470
+ case ValDefs (mparams) :: _ if mparams.exists(referencesBoundName ) =>
457
471
params :: mparamss
458
472
case ValDefs (mparams @ (mparam :: _)) :: Nil if mparam.mods.isOneOf(GivenOrImplicit ) =>
459
473
(params ++ mparams) :: Nil
@@ -467,12 +481,12 @@ object desugar {
467
481
468
482
/** The parameters generated from the contextual bounds of `meth`, as generated by `desugar.defDef` */
469
483
private def evidenceParams (meth : DefDef )(using Context ): List [ValDef ] =
470
- meth.paramss.reverse match {
471
- case ValDefs (vparams @ (vparam :: _)) :: _ if vparam.mods.isOneOf( GivenOrImplicit ) =>
472
- vparams.takeWhile(_.hasAttachment( ContextBoundParam ) )
473
- case _ =>
474
- Nil
475
- }
484
+ for
485
+ case ValDefs (vparams @ (vparam :: _)) <- meth.paramss
486
+ if vparam.mods.isOneOf( GivenOrImplicit )
487
+ param <- vparams.takeWhile(_.hasAttachment( ContextBoundParam ))
488
+ yield
489
+ param
476
490
477
491
@ sharable private val synthetic = Modifiers (Synthetic )
478
492
@@ -490,11 +504,13 @@ object desugar {
490
504
case WitnessNamesAnnot (_) => true
491
505
case _ => false
492
506
493
- private def toDefParam (tparam : TypeDef , keep : KeepAnnotations )(using Context ): TypeDef =
507
+ /** Map type parameter accessor to corresponding method (i.e. constructor) parameter */
508
+ private def toMethParam (tparam : TypeDef , keep : KeepAnnotations )(using Context ): TypeDef =
494
509
val mods = filterAnnots(tparam.rawMods, keep)
495
510
tparam.withMods(mods & EmptyFlags | Param )
496
511
497
- private def toDefParam (vparam : ValDef , keep : KeepAnnotations , keepDefault : Boolean )(using Context ): ValDef = {
512
+ /** Map term parameter accessor to corresponding method (i.e. constructor) parameter */
513
+ private def toMethParam (vparam : ValDef , keep : KeepAnnotations , keepDefault : Boolean )(using Context ): ValDef = {
498
514
val mods = filterAnnots(vparam.rawMods, keep)
499
515
val hasDefault = if keepDefault then HasDefault else EmptyFlags
500
516
// Need to ensure that tree is duplicated since term parameters can be watched
@@ -506,22 +522,16 @@ object desugar {
506
522
.withMods(mods & (GivenOrImplicit | Erased | hasDefault | Tracked ) | Param )
507
523
}
508
524
509
- def mkApply (fn : Tree , paramss : List [ParamClause ])(using Context ): Tree =
510
- paramss.foldLeft(fn) { (fn, params) => params match
511
- case TypeDefs (params) =>
512
- TypeApply (fn, params.map(refOfDef))
513
- case (vparam : ValDef ) :: _ if vparam.mods.is(Given ) =>
514
- Apply (fn, params.map(refOfDef)).setApplyKind(ApplyKind .Using )
515
- case _ =>
516
- Apply (fn, params.map(refOfDef))
517
- }
518
-
525
+ /** Desugar type def (not param): Under x.moduliity this can expand
526
+ * context bounds, which are expanded to evidence ValDefs. These will
527
+ * ultimately map to deferred givens.
528
+ */
519
529
def typeDef (tdef : TypeDef )(using Context ): Tree =
520
530
val evidenceBuf = new ListBuffer [ValDef ]
521
531
val result = desugarContextBounds(
522
532
tdef, evidenceBuf,
523
533
(tdef.mods.flags.toTermFlags & AccessFlags ) | Lazy | DeferredGivenFlags ,
524
- inventGivenOrExtensionName , Nil )
534
+ inventGivenName , Nil )
525
535
if evidenceBuf.isEmpty then result else Thicket (result :: evidenceBuf.toList)
526
536
527
537
/** The expansion of a class definition. See inline comments for what is involved */
@@ -596,7 +606,7 @@ object desugar {
596
606
// Annotations on class _type_ parameters are set on the derived parameters
597
607
// but not on the constructor parameters. The reverse is true for
598
608
// annotations on class _value_ parameters.
599
- val constrTparams = impliedTparams.map(toDefParam (_, KeepAnnotations .WitnessOnly ))
609
+ val constrTparams = impliedTparams.map(toMethParam (_, KeepAnnotations .WitnessOnly ))
600
610
val constrVparamss =
601
611
if (originalVparamss.isEmpty) { // ensure parameter list is non-empty
602
612
if (isCaseClass)
@@ -607,7 +617,7 @@ object desugar {
607
617
report.error(CaseClassMissingNonImplicitParamList (cdef), namePos)
608
618
ListOfNil
609
619
}
610
- else originalVparamss.nestedMap(toDefParam (_, KeepAnnotations .All , keepDefault = true ))
620
+ else originalVparamss.nestedMap(toMethParam (_, KeepAnnotations .All , keepDefault = true ))
611
621
val derivedTparams =
612
622
constrTparams.zipWithConserve(impliedTparams)((tparam, impliedParam) =>
613
623
derivedTypeParam(tparam).withAnnotations(impliedParam.mods.annotations))
@@ -629,7 +639,7 @@ object desugar {
629
639
defDef(
630
640
addEvidenceParams(
631
641
cpy.DefDef (ddef)(paramss = joinParams(constrTparams, ddef.paramss)),
632
- evidenceParams(constr1).map(toDefParam (_, KeepAnnotations .None , keepDefault = false )))))
642
+ evidenceParams(constr1).map(toMethParam (_, KeepAnnotations .None , keepDefault = false )))))
633
643
case stat =>
634
644
stat
635
645
}
@@ -1147,7 +1157,7 @@ object desugar {
1147
1157
*/
1148
1158
def normalizeName (mdef : MemberDef , impl : Tree )(using Context ): Name = {
1149
1159
var name = mdef.name
1150
- if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName (impl))
1160
+ if (name.isEmpty) name = name.likeSpaced(inventGivenName (impl))
1151
1161
def errPos = mdef.source.atSpan(mdef.nameSpan)
1152
1162
if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) {
1153
1163
val kind = if (name.isTypeName) " class" else " object"
@@ -1194,7 +1204,7 @@ object desugar {
1194
1204
end makePolyFunctionType
1195
1205
1196
1206
/** Invent a name for an anonympus given of type or template `impl`. */
1197
- def inventGivenOrExtensionName (impl : Tree )(using Context ): SimpleName =
1207
+ def inventGivenName (impl : Tree )(using Context ): SimpleName =
1198
1208
val str = impl match
1199
1209
case impl : Template =>
1200
1210
if impl.parents.isEmpty then
@@ -1206,6 +1216,10 @@ object desugar {
1206
1216
" given_" ++ inventTypeName(impl)
1207
1217
str.toTermName.asSimpleName
1208
1218
1219
+ /** Extract a synthesized given name from a type tree. This is used for
1220
+ * both anonymous givens and (under x.modularity) deferred givens.
1221
+ * @param followArgs If true include argument types in the name
1222
+ */
1209
1223
private class NameExtractor (followArgs : Boolean ) extends UntypedTreeAccumulator [String ] {
1210
1224
private def extractArgs (args : List [Tree ])(using Context ): String =
1211
1225
args.map(argNameExtractor.apply(" " , _)).mkString(" _" )
0 commit comments