@@ -12,6 +12,7 @@ import collection.mutable
12
12
import reporting .*
13
13
import Checking .{checkNoPrivateLeaks , checkNoWildcard }
14
14
import cc .CaptureSet
15
+ import util .Property
15
16
import transform .Splicer
16
17
17
18
trait TypeAssigner {
@@ -270,36 +271,43 @@ trait TypeAssigner {
270
271
untpd.cpy.Super (tree)(qual, tree.mix)
271
272
.withType(superType(qual.tpe, tree.mix, mixinClass, tree.srcPos))
272
273
274
+ private type SkolemBuffer = mutable.ListBuffer [(Tree , SkolemType )]
275
+
273
276
/** Substitute argument type `argType` for parameter `pref` in type `tp`,
274
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.
275
280
*/
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 =
277
283
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)
281
289
282
290
/** Substitute types of all arguments `args` for corresponding `params` in `tp`.
283
291
* The number of parameters `params` may exceed the number of arguments.
284
292
* In this case, only the common prefix is substituted.
293
+ * Skolems generated by `safeSubstParam` are stored in `skolems`.
285
294
*/
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)
290
300
case Nil =>
291
301
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
297
302
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.tpes)
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 = {
@@ -570,6 +584,12 @@ trait TypeAssigner {
570
584
}
571
585
572
586
object 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
+
573
593
def seqLitType (tree : untpd.SeqLiteral , elemType : Type )(using Context ) = tree match
574
594
case tree : untpd.JavaSeqLiteral => defn.ArrayOf (elemType)
575
595
case _ => if ctx.erasedTypes then defn.SeqType else defn.SeqType .appliedTo(elemType)
0 commit comments