@@ -12,6 +12,7 @@ import collection.mutable
1212import reporting .*
1313import Checking .{checkNoPrivateLeaks , checkNoWildcard }
1414import cc .CaptureSet
15+ import util .Property
1516import transform .Splicer
1617
1718trait TypeAssigner {
@@ -270,36 +271,43 @@ trait TypeAssigner {
270271 untpd.cpy.Super (tree)(qual, tree.mix)
271272 .withType(superType(qual.tpe, tree.mix, mixinClass, tree.srcPos))
272273
274+ private type SkolemBuffer = mutable.ListBuffer [(Tree , SkolemType )]
275+
273276 /** Substitute argument type `argType` for parameter `pref` in type `tp`,
274277 * skolemizing the argument type if it is not stable and `pref` occurs in `tp`.
278+ * If skolemization happens the new SkolemType is passed to `recordSkolem`
279+ * provided the latter is non-null.
275280 */
276- def safeSubstParam (tp : Type , pref : ParamRef , argType : Type )(using Context ): Type = {
281+ def safeSubstParam (tp : Type , pref : ParamRef , argType : Type ,
282+ recordSkolem : (SkolemType => Unit ) | Null = null )(using Context ): Type =
277283 val tp1 = tp.substParam(pref, argType)
278- if ((tp1 eq tp) || argType.isStable) tp1
279- else tp.substParam(pref, SkolemType (argType.widen))
280- }
284+ if (tp1 eq tp) || argType.isStable then tp1
285+ else
286+ val narrowed = SkolemType (argType.widen)
287+ if recordSkolem != null then recordSkolem(narrowed)
288+ tp.substParam(pref, narrowed)
281289
282290 /** Substitute types of all arguments `args` for corresponding `params` in `tp`.
283291 * The number of parameters `params` may exceed the number of arguments.
284292 * In this case, only the common prefix is substituted.
293+ * Skolems generated by `safeSubstParam` are stored in `skolems`.
285294 */
286- def safeSubstParams (tp : Type , params : List [ParamRef ], argTypes : List [Type ])(using Context ): Type = argTypes match {
287- case argType :: argTypes1 =>
288- val tp1 = safeSubstParam(tp, params.head, argType)
289- safeSubstParams(tp1, params.tail, argTypes1)
295+ private def safeSubstParams (tp : Type , params : List [ParamRef ],
296+ args : List [Tree ], skolems : SkolemBuffer )(using Context ): Type = args match
297+ case arg :: args1 =>
298+ val tp1 = safeSubstParam(tp, params.head, arg.tpe, sk => skolems += ((arg, sk)))
299+ safeSubstParams(tp1, params.tail, args1, skolems)
290300 case Nil =>
291301 tp
292- }
293-
294- def safeSubstMethodParams (mt : MethodType , argTypes : List [Type ])(using Context ): Type =
295- if mt.isResultDependent then safeSubstParams(mt.resultType, mt.paramRefs, argTypes)
296- else mt.resultType
297302
298303 def assignType (tree : untpd.Apply , fn : Tree , args : List [Tree ])(using Context ): Apply = {
304+ var skolems : SkolemBuffer | Null = null
299305 val ownType = fn.tpe.widen match {
300306 case fntpe : MethodType =>
301307 if fntpe.paramInfos.hasSameLengthAs(args) || ctx.phase.prev.relaxedTyping then
302- if fntpe.isResultDependent then safeSubstMethodParams(fntpe, args.tpes)
308+ if fntpe.isResultDependent then
309+ skolems = new mutable.ListBuffer ()
310+ safeSubstParams(fntpe.resultType, fntpe.paramRefs, args, skolems.nn)
303311 else fntpe.resultType // fast path optimization
304312 else
305313 val erroringPhase =
@@ -312,7 +320,13 @@ trait TypeAssigner {
312320 if (ctx.settings.Ydebug .value) new FatalError (" " ).printStackTrace()
313321 errorType(err.takesNoParamsMsg(fn, " " ), tree.srcPos)
314322 }
315- ConstFold .Apply (tree.withType(ownType))
323+ val app = tree.withType(ownType)
324+ if skolems != null
325+ && skolems.nn.nonEmpty // @notional why is `.nn` needed here?
326+ && skolems.nn.size == skolems.nn.toSet.size // each skolemized argument is unique
327+ then
328+ app.putAttachment(SkolemizedArgs , skolems.nn.toMap)
329+ ConstFold .Apply (app)
316330 }
317331
318332 def assignType (tree : untpd.TypeApply , fn : Tree , args : List [Tree ])(using Context ): TypeApply = {
@@ -570,6 +584,12 @@ trait TypeAssigner {
570584}
571585
572586object TypeAssigner extends TypeAssigner :
587+
588+ /** An attachment on an application indicating a map from arguments to the skolem types
589+ * that were created in safeSubstParams.
590+ */
591+ private [typer] val SkolemizedArgs = new Property .Key [Map [tpd.Tree , SkolemType ]]
592+
573593 def seqLitType (tree : untpd.SeqLiteral , elemType : Type )(using Context ) = tree match
574594 case tree : untpd.JavaSeqLiteral => defn.ArrayOf (elemType)
575595 case _ => if ctx.erasedTypes then defn.SeqType else defn.SeqType .appliedTo(elemType)
0 commit comments