@@ -271,35 +271,43 @@ trait TypeAssigner {
271
271
untpd.cpy.Super (tree)(qual, tree.mix)
272
272
.withType(superType(qual.tpe, tree.mix, mixinClass, tree.srcPos))
273
273
274
+ private type SkolemBuffer = mutable.ListBuffer [(Tree , SkolemType )]
275
+
274
276
/** Substitute argument type `argType` for parameter `pref` in type `tp`,
275
277
* 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.
276
280
*/
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 =
278
283
val tp1 = tp.substParam(pref, argType)
279
284
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)
282
289
283
290
/** Substitute types of all arguments `args` for corresponding `params` in `tp`.
284
291
* The number of parameters `params` may exceed the number of arguments.
285
292
* In this case, only the common prefix is substituted.
293
+ * Skolems generated by `safeSubstParam` are stored in `skolems`.
286
294
*/
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
288
297
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 )
291
300
case Nil =>
292
301
tp
293
302
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
-
298
303
def assignType (tree : untpd.Apply , fn : Tree , args : List [Tree ])(using Context ): Apply = {
304
+ var skolems : SkolemBuffer | Null = null
299
305
val ownType = fn.tpe.widen match {
300
306
case fntpe : MethodType =>
301
307
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)
303
311
else fntpe.resultType // fast path optimization
304
312
else
305
313
val erroringPhase =
@@ -312,7 +320,13 @@ trait TypeAssigner {
312
320
if (ctx.settings.Ydebug .value) new FatalError (" " ).printStackTrace()
313
321
errorType(err.takesNoParamsMsg(fn, " " ), tree.srcPos)
314
322
}
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)
316
330
}
317
331
318
332
def assignType (tree : untpd.TypeApply , fn : Tree , args : List [Tree ])(using Context ): TypeApply = {
@@ -571,25 +585,10 @@ trait TypeAssigner {
571
585
572
586
object TypeAssigner extends TypeAssigner :
573
587
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 .
576
590
*/
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 ]]
593
592
594
593
def seqLitType (tree : untpd.SeqLiteral , elemType : Type )(using Context ) = tree match
595
594
case tree : untpd.JavaSeqLiteral => defn.ArrayOf (elemType)
0 commit comments