@@ -30,6 +30,7 @@ import config.Feature
3030import collection .mutable
3131import config .Printers .{overload , typr , unapp }
3232import TypeApplications ._
33+ import Annotations .Annotation
3334
3435import Constants .{Constant , IntTag }
3536import Denotations .SingleDenotation
@@ -210,63 +211,81 @@ object Applications {
210211 def wrapDefs (defs : mutable.ListBuffer [Tree ] | Null , tree : Tree )(using Context ): Tree =
211212 if (defs != null && defs.nonEmpty) tpd.Block (defs.toList, tree) else tree
212213
214+ /** Optionally, if `sym` is a symbol created by `resolveMapped`, i.e. representing
215+ * a mapped alternative, the original prefix of the alternative and the number of
216+ * skipped term parameters.
217+ */
218+ private def mappedAltInfo (sym : Symbol )(using Context ): Option [(Type , Int )] =
219+ for ann <- sym.getAnnotation(defn.MappedAlternativeAnnot ) yield
220+ val AppliedType (_, pre :: ConstantType (c) :: Nil ) = ann.tree.tpe: @ unchecked
221+ (pre, c.intValue)
222+
213223 /** Find reference to default parameter getter for parameter #n in current
214- * parameter list, or NoType if none was found
215- */
224+ * parameter list, or EmptyTree if none was found.
225+ * @param fn the tree referring to the function part of this call
226+ * @param n the index of the parameter in the parameter list of the call
227+ * @param testOnly true iff we just to find out whether a getter exists
228+ */
216229 def findDefaultGetter (fn : Tree , n : Int , testOnly : Boolean )(using Context ): Tree =
217- if fn.symbol.isTerm then
230+ def reifyPrefix (pre : Type ): Tree = pre match
231+ case pre : SingletonType => singleton(pre, needLoad = ! testOnly)
232+ case pre if testOnly =>
233+ // In this case it is safe to skolemize now; we will produce a stable prefix for the actual call.
234+ ref(pre.narrow)
235+ case _ => EmptyTree
236+
237+ if fn.symbol.hasDefaultParams then
218238 val meth = fn.symbol.asTerm
219- val receiver : Tree = methPart(fn) match {
220- case Select (receiver, _) => receiver
221- case mr => mr.tpe.normalizedPrefix match {
222- case mr : TermRef => ref(mr)
223- case mr : ThisType => singleton(mr)
224- case mr =>
225- if testOnly then
226- // In this case it is safe to skolemize now; we will produce a stable prefix for the actual call.
227- ref(mr.narrow)
228- else
229- EmptyTree
230- }
231- }
232- val getterPrefix =
233- if (meth.is(Synthetic ) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name
234- def getterName = DefaultGetterName (getterPrefix, n + numArgs(fn))
235- if ! meth.hasDefaultParams then
236- EmptyTree
237- else if (receiver.isEmpty) {
238- def findGetter (cx : Context ): Tree =
239- if (cx eq NoContext ) EmptyTree
240- else if (cx.scope != cx.outer.scope &&
241- cx.denotNamed(meth.name).hasAltWith(_.symbol == meth)) {
242- val denot = cx.denotNamed(getterName)
243- if (denot.exists) ref(TermRef (cx.owner.thisType, getterName, denot))
244- else findGetter(cx.outer)
245- }
239+ val idx = n + numArgs(fn)
240+ methPart(fn) match
241+ case Select (receiver, _) =>
242+ findDefaultGetter(meth, receiver, idx)
243+ case mr => mappedAltInfo(meth) match
244+ case Some ((pre, skipped)) =>
245+ findDefaultGetter(meth, reifyPrefix(pre), idx + skipped)
246+ case None =>
247+ findDefaultGetter(meth, reifyPrefix(mr.tpe.normalizedPrefix), idx)
248+ else EmptyTree // structural applies don't have symbols or defaults
249+ end findDefaultGetter
250+
251+ /** Find reference to default parameter getter for method `meth` numbered `idx`
252+ * selected from given `receiver`, or EmptyTree if none was found.
253+ * @param meth the called method (can be mapped by resolveMapped)
254+ * @param receiver the receiver of the original method call, which determines
255+ * where default getters are found
256+ * @param idx the index of the searched for default getter, as encoded in its name
257+ */
258+ def findDefaultGetter (meth : TermSymbol , receiver : Tree , idx : Int )(using Context ): Tree =
259+ val getterPrefix =
260+ if (meth.is(Synthetic ) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name
261+ val getterName = DefaultGetterName (getterPrefix, idx)
262+
263+ if receiver.isEmpty then
264+ def findGetter (cx : Context ): Tree =
265+ if cx eq NoContext then EmptyTree
266+ else if cx.scope != cx.outer.scope
267+ && cx.denotNamed(meth.name).hasAltWith(_.symbol == meth) then
268+ val denot = cx.denotNamed(getterName)
269+ if denot.exists then ref(TermRef (cx.owner.thisType, getterName, denot))
246270 else findGetter(cx.outer)
247- findGetter(ctx)
248- }
249- else {
250- def selectGetter (qual : Tree ): Tree = {
251- val getterDenot = qual.tpe.member(getterName)
252- if (getterDenot.exists) qual.select(TermRef (qual.tpe, getterName, getterDenot))
253- else EmptyTree
254- }
255- if (! meth.isClassConstructor)
256- selectGetter(receiver)
257- else {
258- // default getters for class constructors are found in the companion object
259- val cls = meth.owner
260- val companion = cls.companionModule
261- if (companion.isTerm) {
262- val prefix = receiver.tpe.baseType(cls).normalizedPrefix
263- if (prefix.exists) selectGetter(ref(TermRef (prefix, companion.asTerm)))
264- else EmptyTree
265- }
271+ else findGetter(cx.outer)
272+ findGetter(ctx)
273+ else
274+ def selectGetter (qual : Tree ): Tree =
275+ val getterDenot = qual.tpe.member(getterName)
276+ if (getterDenot.exists) qual.select(TermRef (qual.tpe, getterName, getterDenot))
277+ else EmptyTree
278+ if ! meth.isClassConstructor then
279+ selectGetter(receiver)
280+ else
281+ // default getters for class constructors are found in the companion object
282+ val cls = meth.owner
283+ val companion = cls.companionModule
284+ if companion.isTerm then
285+ val prefix = receiver.tpe.baseType(cls).normalizedPrefix
286+ if prefix.exists then selectGetter(ref(TermRef (prefix, companion.asTerm)))
266287 else EmptyTree
267- }
268- }
269- else EmptyTree // structural applies don't have symbols or defaults
288+ else EmptyTree
270289 end findDefaultGetter
271290
272291 /** Splice new method reference `meth` into existing application `app` */
@@ -1937,9 +1956,8 @@ trait Applications extends Compatibility {
19371956 def isVarArgs = ptypes.nonEmpty && ptypes.last.isRepeatedParam
19381957 def numDefaultParams =
19391958 if alt.symbol.hasDefaultParams then
1940- trimParamss(tp, alt.symbol.rawParamss) match
1941- case params :: _ => params.count(_.is(HasDefault ))
1942- case _ => 0
1959+ val fn = ref(alt, needLoad = false )
1960+ ptypes.indices.count(n => ! findDefaultGetter(fn, n, testOnly = true ).isEmpty)
19431961 else 0
19441962 if numParams < numArgs then isVarArgs
19451963 else if numParams == numArgs then true
@@ -2088,13 +2106,22 @@ trait Applications extends Compatibility {
20882106 }
20892107 end resolveOverloaded1
20902108
2091- /** The largest suffix of `paramss` that has the same first parameter name as `t` */
2092- def trimParamss (t : Type , paramss : List [List [Symbol ]])(using Context ): List [List [Symbol ]] = t match
2109+ /** The largest suffix of `paramss` that has the same first parameter name as `t`,
2110+ * plus the number of term parameters in `paramss` that come before that suffix.
2111+ */
2112+ def trimParamss (t : Type , paramss : List [List [Symbol ]])(using Context ): (List [List [Symbol ]], Int ) = t match
20932113 case MethodType (Nil ) => trimParamss(t.resultType, paramss)
20942114 case t : MethodOrPoly =>
20952115 val firstParamName = t.paramNames.head
2096- paramss.dropWhile(_.head.name != firstParamName)
2097- case _ => Nil
2116+ def recur (pss : List [List [Symbol ]], skipped : Int ): (List [List [Symbol ]], Int ) =
2117+ (pss : @ unchecked) match
2118+ case (ps @ (p :: _)) :: pss1 =>
2119+ if p.name == firstParamName then (pss, skipped)
2120+ else recur(pss1, if p.name.isTermName then skipped + ps.length else skipped)
2121+ case Nil =>
2122+ (pss, skipped)
2123+ recur(paramss, 0 )
2124+ case _ => (Nil , 0 )
20982125
20992126 /** Resolve overloading by mapping to a different problem where each alternative's
21002127 * type is mapped with `f`, alternatives with non-existing types are dropped, and the
@@ -2104,8 +2131,19 @@ trait Applications extends Compatibility {
21042131 val reverseMapping = alts.flatMap { alt =>
21052132 val t = f(alt)
21062133 if t.exists then
2134+ val (trimmed, skipped) = trimParamss(t, alt.symbol.rawParamss)
21072135 val mappedSym = alt.symbol.asTerm.copy(info = t)
2108- mappedSym.rawParamss = trimParamss(t, alt.symbol.rawParamss)
2136+ mappedSym.rawParamss = trimmed
2137+ val (pre, totalSkipped) = mappedAltInfo(alt.symbol) match
2138+ case Some ((pre, prevSkipped)) =>
2139+ mappedSym.removeAnnotation(defn.MappedAlternativeAnnot )
2140+ (pre, skipped + prevSkipped)
2141+ case None =>
2142+ (alt.prefix, skipped)
2143+ mappedSym.addAnnotation(
2144+ Annotation (TypeTree (
2145+ defn.MappedAlternativeAnnot .typeRef.appliedTo(
2146+ pre, ConstantType (Constant (totalSkipped))))))
21092147 Some ((TermRef (NoPrefix , mappedSym), alt))
21102148 else
21112149 None
0 commit comments