@@ -271,35 +271,43 @@ trait TypeAssigner {
271271 untpd.cpy.Super (tree)(qual, tree.mix)
272272 .withType(superType(qual.tpe, tree.mix, mixinClass, tree.srcPos))
273273
274+ private type SkolemBuffer = mutable.ListBuffer [(Tree , SkolemType )]
275+
274276 /** Substitute argument type `argType` for parameter `pref` in type `tp`,
275277 * 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.
276280 */
277- def safeSubstParam (tp : Type , pref : ParamRef , argType : Type , arg : Tree | Null = null )(using Context ): Type = {
281+ def safeSubstParam (tp : Type , pref : ParamRef , argType : Type ,
282+ recordSkolem : (SkolemType => Unit ) | Null = null )(using Context ): Type =
278283 val tp1 = tp.substParam(pref, argType)
279284 if (tp1 eq tp) || argType.isStable then tp1
280- else tp.substParam(pref, skolemizeArgType(argType.widen, arg))
281- }
285+ else
286+ val narrowed = SkolemType (argType.widen)
287+ if recordSkolem != null then recordSkolem(narrowed)
288+ tp.substParam(pref, narrowed)
282289
283290 /** Substitute types of all arguments `args` for corresponding `params` in `tp`.
284291 * The number of parameters `params` may exceed the number of arguments.
285292 * In this case, only the common prefix is substituted.
293+ * Skolems generated by `safeSubstParam` are stored in `skolems`.
286294 */
287- def safeSubstParams (tp : Type , params : List [ParamRef ], args : List [Tree ])(using Context ): Type = args match
295+ private def safeSubstParams (tp : Type , params : List [ParamRef ],
296+ args : List [Tree ], skolems : SkolemBuffer )(using Context ): Type = args match
288297 case arg :: args1 =>
289- val tp1 = safeSubstParam(tp, params.head, arg.tpe, arg)
290- safeSubstParams(tp1, params.tail, args1)
298+ val tp1 = safeSubstParam(tp, params.head, arg.tpe, sk => skolems += (( arg, sk)) )
299+ safeSubstParams(tp1, params.tail, args1, skolems )
291300 case Nil =>
292301 tp
293302
294- def safeSubstMethodParams (mt : MethodType , args : List [Tree ])(using Context ): Type =
295- if mt.isResultDependent then safeSubstParams(mt.resultType, mt.paramRefs, args)
296- else mt.resultType
297-
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)
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 = {
@@ -571,25 +585,10 @@ trait TypeAssigner {
571585
572586object TypeAssigner extends TypeAssigner :
573587
574- /** An attachment on an argument in an application indicating that the argument's
575- * type was converted to the given skolem type .
588+ /** An attachment on an application indicating a map from arguments to the skolem types
589+ * that were created in safeSubstParams .
576590 */
577- private val Skolemized = new Property .StickyKey [SkolemType ]
578-
579- /** A skolem type wrapping `argType`, associated with `arg` if it is non-null.
580- * Skolem types for the same arguments with equal underlying `argType`s are re-used.
581- */
582- def skolemizeArgType (argType : Type , arg : tpd.Tree | Null )(using Context ): Type =
583- if arg == null then
584- SkolemType (argType)
585- else
586- arg.getAttachment(Skolemized ) match
587- case Some (sk @ SkolemType (tp)) if argType frozen_=:= tp =>
588- sk
589- case _ =>
590- val sk = SkolemType (argType)
591- arg.putAttachment(Skolemized , sk)
592- sk
591+ private [typer] val SkolemizedArgs = new Property .Key [Map [tpd.Tree , SkolemType ]]
593592
594593 def seqLitType (tree : untpd.SeqLiteral , elemType : Type )(using Context ) = tree match
595594 case tree : untpd.JavaSeqLiteral => defn.ArrayOf (elemType)
0 commit comments