@@ -30,6 +30,7 @@ import config.Feature
30
30
import collection .mutable
31
31
import config .Printers .{overload , typr , unapp }
32
32
import TypeApplications ._
33
+ import Annotations .Annotation
33
34
34
35
import Constants .{Constant , IntTag }
35
36
import Denotations .SingleDenotation
@@ -210,63 +211,81 @@ object Applications {
210
211
def wrapDefs (defs : mutable.ListBuffer [Tree ] | Null , tree : Tree )(using Context ): Tree =
211
212
if (defs != null && defs.nonEmpty) tpd.Block (defs.toList, tree) else tree
212
213
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
+
213
223
/** 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
+ */
216
229
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
218
238
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))
246
270
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)))
266
287
else EmptyTree
267
- }
268
- }
269
- else EmptyTree // structural applies don't have symbols or defaults
288
+ else EmptyTree
270
289
end findDefaultGetter
271
290
272
291
/** Splice new method reference `meth` into existing application `app` */
@@ -1937,9 +1956,8 @@ trait Applications extends Compatibility {
1937
1956
def isVarArgs = ptypes.nonEmpty && ptypes.last.isRepeatedParam
1938
1957
def numDefaultParams =
1939
1958
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)
1943
1961
else 0
1944
1962
if numParams < numArgs then isVarArgs
1945
1963
else if numParams == numArgs then true
@@ -2088,13 +2106,22 @@ trait Applications extends Compatibility {
2088
2106
}
2089
2107
end resolveOverloaded1
2090
2108
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
2093
2113
case MethodType (Nil ) => trimParamss(t.resultType, paramss)
2094
2114
case t : MethodOrPoly =>
2095
2115
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 )
2098
2125
2099
2126
/** Resolve overloading by mapping to a different problem where each alternative's
2100
2127
* type is mapped with `f`, alternatives with non-existing types are dropped, and the
@@ -2104,8 +2131,19 @@ trait Applications extends Compatibility {
2104
2131
val reverseMapping = alts.flatMap { alt =>
2105
2132
val t = f(alt)
2106
2133
if t.exists then
2134
+ val (trimmed, skipped) = trimParamss(t, alt.symbol.rawParamss)
2107
2135
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))))))
2109
2147
Some ((TermRef (NoPrefix , mappedSym), alt))
2110
2148
else
2111
2149
None
0 commit comments