@@ -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 : mutable.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 = mutable.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:
@@ -332,9 +347,9 @@ object desugar {
332
347
333
348
def getterParamss (n : Int ): List [ParamClause ] =
334
349
mapParamss(takeUpTo(paramssNoRHS, n)) {
335
- tparam => dropContextBounds(toDefParam (tparam, KeepAnnotations .All ))
350
+ tparam => dropContextBounds(toMethParam (tparam, KeepAnnotations .All ))
336
351
} {
337
- vparam => toDefParam (vparam, KeepAnnotations .All , keepDefault = false )
352
+ vparam => toMethParam (vparam, KeepAnnotations .All , keepDefault = false )
338
353
}
339
354
340
355
def defaultGetters (paramss : List [ParamClause ], n : Int ): List [DefDef ] = paramss match
@@ -429,32 +444,30 @@ object desugar {
429
444
* The position of the added parameters is determined as follows:
430
445
*
431
446
* - If there is an existing parameter list that refers to one of the added
432
- * parameters in one of its parameter types, add the new parameters
433
- * in front of the first such parameter list.
434
- * - 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,
435
450
* join the new parameters in front of this parameter list, creating one
436
- * parameter list (this is equilavent to Scala 2's scheme).
451
+ * parameter list (this is equivalent to Scala 2's scheme).
437
452
* - Otherwise, add the new parameter list at the end as a separate parameter clause.
438
453
*/
439
454
private def addEvidenceParams (meth : DefDef , params : List [ValDef ])(using Context ): DefDef =
440
455
if params.isEmpty then return meth
441
456
442
- var boundNames = params.map(_.name).toSet
457
+ var boundNames = params.map(_.name).toSet // all evidence parameter + context bound proxy names
443
458
for mparams <- meth.paramss; mparam <- mparams do
444
459
mparam match
445
460
case tparam : TypeDef if tparam.mods.annotations.exists(WitnessNamesAnnot .unapply(_).isDefined) =>
446
461
boundNames += tparam.name.toTermName
447
462
case _ =>
448
463
449
- // println(i"add ev params ${meth.name}, ${boundNames.toList}")
450
-
451
- def references (vdef : ValDef ): Boolean =
464
+ def referencesBoundName (vdef : ValDef ): Boolean =
452
465
vdef.tpt.existsSubTree:
453
466
case Ident (name : TermName ) => boundNames.contains(name)
454
467
case _ => false
455
468
456
469
def recur (mparamss : List [ParamClause ]): List [ParamClause ] = mparamss match
457
- case ValDefs (mparams) :: _ if mparams.exists(references ) =>
470
+ case ValDefs (mparams) :: _ if mparams.exists(referencesBoundName ) =>
458
471
params :: mparamss
459
472
case ValDefs (mparams @ (mparam :: _)) :: Nil if mparam.mods.isOneOf(GivenOrImplicit ) =>
460
473
(params ++ mparams) :: Nil
@@ -468,12 +481,12 @@ object desugar {
468
481
469
482
/** The parameters generated from the contextual bounds of `meth`, as generated by `desugar.defDef` */
470
483
private def evidenceParams (meth : DefDef )(using Context ): List [ValDef ] =
471
- meth.paramss.reverse match {
472
- case ValDefs (vparams @ (vparam :: _)) :: _ if vparam.mods.isOneOf( GivenOrImplicit ) =>
473
- vparams.takeWhile(_.hasAttachment( ContextBoundParam ) )
474
- case _ =>
475
- Nil
476
- }
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
477
490
478
491
@ sharable private val synthetic = Modifiers (Synthetic )
479
492
@@ -491,11 +504,13 @@ object desugar {
491
504
case WitnessNamesAnnot (_) => true
492
505
case _ => false
493
506
494
- 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 =
495
509
val mods = filterAnnots(tparam.rawMods, keep)
496
510
tparam.withMods(mods & EmptyFlags | Param )
497
511
498
- 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 = {
499
514
val mods = filterAnnots(vparam.rawMods, keep)
500
515
val hasDefault = if keepDefault then HasDefault else EmptyFlags
501
516
// Need to ensure that tree is duplicated since term parameters can be watched
@@ -507,22 +522,16 @@ object desugar {
507
522
.withMods(mods & (GivenOrImplicit | Erased | hasDefault | Tracked ) | Param )
508
523
}
509
524
510
- def mkApply (fn : Tree , paramss : List [ParamClause ])(using Context ): Tree =
511
- paramss.foldLeft(fn) { (fn, params) => params match
512
- case TypeDefs (params) =>
513
- TypeApply (fn, params.map(refOfDef))
514
- case (vparam : ValDef ) :: _ if vparam.mods.is(Given ) =>
515
- Apply (fn, params.map(refOfDef)).setApplyKind(ApplyKind .Using )
516
- case _ =>
517
- Apply (fn, params.map(refOfDef))
518
- }
519
-
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
+ */
520
529
def typeDef (tdef : TypeDef )(using Context ): Tree =
521
530
val evidenceBuf = new mutable.ListBuffer [ValDef ]
522
531
val result = desugarContextBounds(
523
532
tdef, evidenceBuf,
524
533
(tdef.mods.flags.toTermFlags & AccessFlags ) | Lazy | DeferredGivenFlags ,
525
- inventGivenOrExtensionName , Nil )
534
+ inventGivenName , Nil )
526
535
if evidenceBuf.isEmpty then result else Thicket (result :: evidenceBuf.toList)
527
536
528
537
/** The expansion of a class definition. See inline comments for what is involved */
@@ -597,7 +606,7 @@ object desugar {
597
606
// Annotations on class _type_ parameters are set on the derived parameters
598
607
// but not on the constructor parameters. The reverse is true for
599
608
// annotations on class _value_ parameters.
600
- val constrTparams = impliedTparams.map(toDefParam (_, KeepAnnotations .WitnessOnly ))
609
+ val constrTparams = impliedTparams.map(toMethParam (_, KeepAnnotations .WitnessOnly ))
601
610
val constrVparamss =
602
611
if (originalVparamss.isEmpty) { // ensure parameter list is non-empty
603
612
if (isCaseClass)
@@ -608,7 +617,7 @@ object desugar {
608
617
report.error(CaseClassMissingNonImplicitParamList (cdef), namePos)
609
618
ListOfNil
610
619
}
611
- else originalVparamss.nestedMap(toDefParam (_, KeepAnnotations .All , keepDefault = true ))
620
+ else originalVparamss.nestedMap(toMethParam (_, KeepAnnotations .All , keepDefault = true ))
612
621
val derivedTparams =
613
622
constrTparams.zipWithConserve(impliedTparams)((tparam, impliedParam) =>
614
623
derivedTypeParam(tparam).withAnnotations(impliedParam.mods.annotations))
@@ -630,7 +639,7 @@ object desugar {
630
639
defDef(
631
640
addEvidenceParams(
632
641
cpy.DefDef (ddef)(paramss = joinParams(constrTparams, ddef.paramss)),
633
- evidenceParams(constr1).map(toDefParam (_, KeepAnnotations .None , keepDefault = false )))))
642
+ evidenceParams(constr1).map(toMethParam (_, KeepAnnotations .None , keepDefault = false )))))
634
643
case stat =>
635
644
stat
636
645
}
@@ -1148,7 +1157,7 @@ object desugar {
1148
1157
*/
1149
1158
def normalizeName (mdef : MemberDef , impl : Tree )(using Context ): Name = {
1150
1159
var name = mdef.name
1151
- if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName (impl))
1160
+ if (name.isEmpty) name = name.likeSpaced(inventGivenName (impl))
1152
1161
def errPos = mdef.source.atSpan(mdef.nameSpan)
1153
1162
if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) {
1154
1163
val kind = if (name.isTypeName) " class" else " object"
@@ -1195,7 +1204,7 @@ object desugar {
1195
1204
end makePolyFunctionType
1196
1205
1197
1206
/** Invent a name for an anonympus given of type or template `impl`. */
1198
- def inventGivenOrExtensionName (impl : Tree )(using Context ): SimpleName =
1207
+ def inventGivenName (impl : Tree )(using Context ): SimpleName =
1199
1208
val str = impl match
1200
1209
case impl : Template =>
1201
1210
if impl.parents.isEmpty then
@@ -1207,6 +1216,10 @@ object desugar {
1207
1216
" given_" ++ inventTypeName(impl)
1208
1217
str.toTermName.asSimpleName
1209
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
+ */
1210
1223
private class NameExtractor (followArgs : Boolean ) extends UntypedTreeAccumulator [String ] {
1211
1224
private def extractArgs (args : List [Tree ])(using Context ): String =
1212
1225
args.map(argNameExtractor.apply(" " , _)).mkString(" _" )
0 commit comments