@@ -226,29 +226,40 @@ object desugar {
226226 private def defDef (meth : DefDef , isPrimaryConstructor : Boolean = false )(using Context ): Tree =
227227 addDefaultGetters(elimContextBounds(meth, isPrimaryConstructor))
228228
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+ */
229240 private def desugarContextBounds (
230241 tdef : TypeDef ,
231242 evidenceBuf : mutable.ListBuffer [ValDef ],
232- flags : FlagSet ,
243+ evidenceFlags : FlagSet ,
233244 freshName : untpd.Tree => TermName ,
234245 allParamss : List [ParamClause ])(using Context ): TypeDef =
235246
236247 val evidenceNames = mutable.ListBuffer [TermName ]()
237248
238249 def desugarRhs (rhs : Tree ): Tree = rhs match
239250 case ContextBounds (tbounds, cxbounds) =>
240- val isMember = flags .isAllOf(DeferredGivenFlags )
251+ val isMember = evidenceFlags .isAllOf(DeferredGivenFlags )
241252 for bound <- cxbounds do
242253 val evidenceName = bound match
243254 case ContextBoundTypeTree (_, _, ownName) if ! ownName.isEmpty =>
244- ownName
255+ ownName // if there is an explicitly given name, use it.
245256 case _ if Config .nameSingleContextBounds && ! isMember
246257 && cxbounds.tail.isEmpty && Feature .enabled(Feature .modularity) =>
247258 tdef.name.toTermName
248259 case _ =>
249260 freshName(bound)
250261 evidenceNames += evidenceName
251- val evidenceParam = ValDef (evidenceName, bound, EmptyTree ).withFlags(flags )
262+ val evidenceParam = ValDef (evidenceName, bound, EmptyTree ).withFlags(evidenceFlags )
252263 evidenceParam.pushAttachment(ContextBoundParam , ())
253264 evidenceBuf += evidenceParam
254265 tbounds
@@ -258,9 +269,13 @@ object desugar {
258269 rhs
259270
260271 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.
261276 if Feature .enabled(Feature .modularity)
262277 && evidenceNames.nonEmpty
263- && ! evidenceNames.contains( tdef.name.toTermName)
278+ && ! evidenceBuf.exists(_.name == tdef.name.toTermName)
264279 && ! allParamss.nestedExists(_.name == tdef.name.toTermName)
265280 then
266281 tdef1.withAddedAnnotation:
@@ -332,9 +347,9 @@ object desugar {
332347
333348 def getterParamss (n : Int ): List [ParamClause ] =
334349 mapParamss(takeUpTo(paramssNoRHS, n)) {
335- tparam => dropContextBounds(toDefParam (tparam, KeepAnnotations .All ))
350+ tparam => dropContextBounds(toMethParam (tparam, KeepAnnotations .All ))
336351 } {
337- vparam => toDefParam (vparam, KeepAnnotations .All , keepDefault = false )
352+ vparam => toMethParam (vparam, KeepAnnotations .All , keepDefault = false )
338353 }
339354
340355 def defaultGetters (paramss : List [ParamClause ], n : Int ): List [DefDef ] = paramss match
@@ -429,32 +444,30 @@ object desugar {
429444 * The position of the added parameters is determined as follows:
430445 *
431446 * - 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,
435450 * 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).
437452 * - Otherwise, add the new parameter list at the end as a separate parameter clause.
438453 */
439454 private def addEvidenceParams (meth : DefDef , params : List [ValDef ])(using Context ): DefDef =
440455 if params.isEmpty then return meth
441456
442- var boundNames = params.map(_.name).toSet
457+ var boundNames = params.map(_.name).toSet // all evidence parameter + context bound proxy names
443458 for mparams <- meth.paramss; mparam <- mparams do
444459 mparam match
445460 case tparam : TypeDef if tparam.mods.annotations.exists(WitnessNamesAnnot .unapply(_).isDefined) =>
446461 boundNames += tparam.name.toTermName
447462 case _ =>
448463
449- // println(i"add ev params ${meth.name}, ${boundNames.toList}")
450-
451- def references (vdef : ValDef ): Boolean =
464+ def referencesBoundName (vdef : ValDef ): Boolean =
452465 vdef.tpt.existsSubTree:
453466 case Ident (name : TermName ) => boundNames.contains(name)
454467 case _ => false
455468
456469 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 ) =>
458471 params :: mparamss
459472 case ValDefs (mparams @ (mparam :: _)) :: Nil if mparam.mods.isOneOf(GivenOrImplicit ) =>
460473 (params ++ mparams) :: Nil
@@ -468,12 +481,12 @@ object desugar {
468481
469482 /** The parameters generated from the contextual bounds of `meth`, as generated by `desugar.defDef` */
470483 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
477490
478491 @ sharable private val synthetic = Modifiers (Synthetic )
479492
@@ -491,11 +504,13 @@ object desugar {
491504 case WitnessNamesAnnot (_) => true
492505 case _ => false
493506
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 =
495509 val mods = filterAnnots(tparam.rawMods, keep)
496510 tparam.withMods(mods & EmptyFlags | Param )
497511
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 = {
499514 val mods = filterAnnots(vparam.rawMods, keep)
500515 val hasDefault = if keepDefault then HasDefault else EmptyFlags
501516 // Need to ensure that tree is duplicated since term parameters can be watched
@@ -507,22 +522,16 @@ object desugar {
507522 .withMods(mods & (GivenOrImplicit | Erased | hasDefault | Tracked ) | Param )
508523 }
509524
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+ */
520529 def typeDef (tdef : TypeDef )(using Context ): Tree =
521530 val evidenceBuf = new mutable.ListBuffer [ValDef ]
522531 val result = desugarContextBounds(
523532 tdef, evidenceBuf,
524533 (tdef.mods.flags.toTermFlags & AccessFlags ) | Lazy | DeferredGivenFlags ,
525- inventGivenOrExtensionName , Nil )
534+ inventGivenName , Nil )
526535 if evidenceBuf.isEmpty then result else Thicket (result :: evidenceBuf.toList)
527536
528537 /** The expansion of a class definition. See inline comments for what is involved */
@@ -597,7 +606,7 @@ object desugar {
597606 // Annotations on class _type_ parameters are set on the derived parameters
598607 // but not on the constructor parameters. The reverse is true for
599608 // annotations on class _value_ parameters.
600- val constrTparams = impliedTparams.map(toDefParam (_, KeepAnnotations .WitnessOnly ))
609+ val constrTparams = impliedTparams.map(toMethParam (_, KeepAnnotations .WitnessOnly ))
601610 val constrVparamss =
602611 if (originalVparamss.isEmpty) { // ensure parameter list is non-empty
603612 if (isCaseClass)
@@ -608,7 +617,7 @@ object desugar {
608617 report.error(CaseClassMissingNonImplicitParamList (cdef), namePos)
609618 ListOfNil
610619 }
611- else originalVparamss.nestedMap(toDefParam (_, KeepAnnotations .All , keepDefault = true ))
620+ else originalVparamss.nestedMap(toMethParam (_, KeepAnnotations .All , keepDefault = true ))
612621 val derivedTparams =
613622 constrTparams.zipWithConserve(impliedTparams)((tparam, impliedParam) =>
614623 derivedTypeParam(tparam).withAnnotations(impliedParam.mods.annotations))
@@ -630,7 +639,7 @@ object desugar {
630639 defDef(
631640 addEvidenceParams(
632641 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 )))))
634643 case stat =>
635644 stat
636645 }
@@ -1148,7 +1157,7 @@ object desugar {
11481157 */
11491158 def normalizeName (mdef : MemberDef , impl : Tree )(using Context ): Name = {
11501159 var name = mdef.name
1151- if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName (impl))
1160+ if (name.isEmpty) name = name.likeSpaced(inventGivenName (impl))
11521161 def errPos = mdef.source.atSpan(mdef.nameSpan)
11531162 if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) {
11541163 val kind = if (name.isTypeName) " class" else " object"
@@ -1195,7 +1204,7 @@ object desugar {
11951204 end makePolyFunctionType
11961205
11971206 /** 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 =
11991208 val str = impl match
12001209 case impl : Template =>
12011210 if impl.parents.isEmpty then
@@ -1207,6 +1216,10 @@ object desugar {
12071216 " given_" ++ inventTypeName(impl)
12081217 str.toTermName.asSimpleName
12091218
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+ */
12101223 private class NameExtractor (followArgs : Boolean ) extends UntypedTreeAccumulator [String ] {
12111224 private def extractArgs (args : List [Tree ])(using Context ): String =
12121225 args.map(argNameExtractor.apply(" " , _)).mkString(" _" )
0 commit comments