@@ -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 : ListBuffer [ValDef ],
232- flags : FlagSet ,
243+ evidenceFlags : FlagSet ,
233244 freshName : untpd.Tree => TermName ,
234245 allParamss : List [ParamClause ])(using Context ): TypeDef =
235246
236247 val evidenceNames = 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:
@@ -272,6 +287,7 @@ object desugar {
272287 private def elimContextBounds (meth : DefDef , isPrimaryConstructor : Boolean )(using Context ): DefDef =
273288 val DefDef (_, paramss, tpt, rhs) = meth
274289 val evidenceParamBuf = ListBuffer [ValDef ]()
290+
275291 var seenContextBounds : Int = 0
276292 def freshName (unused : Tree ) =
277293 seenContextBounds += 1 // Start at 1 like FreshNameCreator.
@@ -331,9 +347,9 @@ object desugar {
331347
332348 def getterParamss (n : Int ): List [ParamClause ] =
333349 mapParamss(takeUpTo(paramssNoRHS, n)) {
334- tparam => dropContextBounds(toDefParam (tparam, KeepAnnotations .All ))
350+ tparam => dropContextBounds(toMethParam (tparam, KeepAnnotations .All ))
335351 } {
336- vparam => toDefParam (vparam, KeepAnnotations .All , keepDefault = false )
352+ vparam => toMethParam (vparam, KeepAnnotations .All , keepDefault = false )
337353 }
338354
339355 def defaultGetters (paramss : List [ParamClause ], n : Int ): List [DefDef ] = paramss match
@@ -428,32 +444,30 @@ object desugar {
428444 * The position of the added parameters is determined as follows:
429445 *
430446 * - 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,
434450 * 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).
436452 * - Otherwise, add the new parameter list at the end as a separate parameter clause.
437453 */
438454 private def addEvidenceParams (meth : DefDef , params : List [ValDef ])(using Context ): DefDef =
439455 if params.isEmpty then return meth
440456
441- var boundNames = params.map(_.name).toSet
457+ var boundNames = params.map(_.name).toSet // all evidence parameter + context bound proxy names
442458 for mparams <- meth.paramss; mparam <- mparams do
443459 mparam match
444460 case tparam : TypeDef if tparam.mods.annotations.exists(WitnessNamesAnnot .unapply(_).isDefined) =>
445461 boundNames += tparam.name.toTermName
446462 case _ =>
447463
448- // println(i"add ev params ${meth.name}, ${boundNames.toList}")
449-
450- def references (vdef : ValDef ): Boolean =
464+ def referencesBoundName (vdef : ValDef ): Boolean =
451465 vdef.tpt.existsSubTree:
452466 case Ident (name : TermName ) => boundNames.contains(name)
453467 case _ => false
454468
455469 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 ) =>
457471 params :: mparamss
458472 case ValDefs (mparams @ (mparam :: _)) :: Nil if mparam.mods.isOneOf(GivenOrImplicit ) =>
459473 (params ++ mparams) :: Nil
@@ -467,12 +481,12 @@ object desugar {
467481
468482 /** The parameters generated from the contextual bounds of `meth`, as generated by `desugar.defDef` */
469483 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
476490
477491 @ sharable private val synthetic = Modifiers (Synthetic )
478492
@@ -490,11 +504,13 @@ object desugar {
490504 case WitnessNamesAnnot (_) => true
491505 case _ => false
492506
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 =
494509 val mods = filterAnnots(tparam.rawMods, keep)
495510 tparam.withMods(mods & EmptyFlags | Param )
496511
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 = {
498514 val mods = filterAnnots(vparam.rawMods, keep)
499515 val hasDefault = if keepDefault then HasDefault else EmptyFlags
500516 // Need to ensure that tree is duplicated since term parameters can be watched
@@ -506,22 +522,16 @@ object desugar {
506522 .withMods(mods & (GivenOrImplicit | Erased | hasDefault | Tracked ) | Param )
507523 }
508524
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+ */
519529 def typeDef (tdef : TypeDef )(using Context ): Tree =
520530 val evidenceBuf = new ListBuffer [ValDef ]
521531 val result = desugarContextBounds(
522532 tdef, evidenceBuf,
523533 (tdef.mods.flags.toTermFlags & AccessFlags ) | Lazy | DeferredGivenFlags ,
524- inventGivenOrExtensionName , Nil )
534+ inventGivenName , Nil )
525535 if evidenceBuf.isEmpty then result else Thicket (result :: evidenceBuf.toList)
526536
527537 /** The expansion of a class definition. See inline comments for what is involved */
@@ -596,7 +606,7 @@ object desugar {
596606 // Annotations on class _type_ parameters are set on the derived parameters
597607 // but not on the constructor parameters. The reverse is true for
598608 // annotations on class _value_ parameters.
599- val constrTparams = impliedTparams.map(toDefParam (_, KeepAnnotations .WitnessOnly ))
609+ val constrTparams = impliedTparams.map(toMethParam (_, KeepAnnotations .WitnessOnly ))
600610 val constrVparamss =
601611 if (originalVparamss.isEmpty) { // ensure parameter list is non-empty
602612 if (isCaseClass)
@@ -607,7 +617,7 @@ object desugar {
607617 report.error(CaseClassMissingNonImplicitParamList (cdef), namePos)
608618 ListOfNil
609619 }
610- else originalVparamss.nestedMap(toDefParam (_, KeepAnnotations .All , keepDefault = true ))
620+ else originalVparamss.nestedMap(toMethParam (_, KeepAnnotations .All , keepDefault = true ))
611621 val derivedTparams =
612622 constrTparams.zipWithConserve(impliedTparams)((tparam, impliedParam) =>
613623 derivedTypeParam(tparam).withAnnotations(impliedParam.mods.annotations))
@@ -629,7 +639,7 @@ object desugar {
629639 defDef(
630640 addEvidenceParams(
631641 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 )))))
633643 case stat =>
634644 stat
635645 }
@@ -1147,7 +1157,7 @@ object desugar {
11471157 */
11481158 def normalizeName (mdef : MemberDef , impl : Tree )(using Context ): Name = {
11491159 var name = mdef.name
1150- if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName (impl))
1160+ if (name.isEmpty) name = name.likeSpaced(inventGivenName (impl))
11511161 def errPos = mdef.source.atSpan(mdef.nameSpan)
11521162 if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) {
11531163 val kind = if (name.isTypeName) " class" else " object"
@@ -1194,7 +1204,7 @@ object desugar {
11941204 end makePolyFunctionType
11951205
11961206 /** 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 =
11981208 val str = impl match
11991209 case impl : Template =>
12001210 if impl.parents.isEmpty then
@@ -1206,6 +1216,10 @@ object desugar {
12061216 " given_" ++ inventTypeName(impl)
12071217 str.toTermName.asSimpleName
12081218
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+ */
12091223 private class NameExtractor (followArgs : Boolean ) extends UntypedTreeAccumulator [String ] {
12101224 private def extractArgs (args : List [Tree ])(using Context ): String =
12111225 args.map(argNameExtractor.apply(" " , _)).mkString(" _" )
0 commit comments