@@ -33,15 +33,11 @@ object TypeApplications {
33
33
*/
34
34
object EtaExpansion :
35
35
36
- def apply (tycon : Type )(using Context ): Type =
37
- assert(tycon.typeParams.nonEmpty, tycon)
38
- tycon.etaExpand(tycon.typeParamSymbols)
39
-
40
36
/** Test that the parameter bounds in a hk type lambda `[X1,...,Xn] => C[X1, ..., Xn]`
41
37
* contain the bounds of the type parameters of `C`. This is necessary to be able to
42
38
* contract the hk lambda to `C`.
43
39
*/
44
- private def weakerBounds (tp : HKTypeLambda , tparams : List [ ParamInfo ] )(using Context ): Boolean =
40
+ private def weakerBounds (tp : HKTypeLambda , fn : Type )(using Context ): Boolean =
45
41
val onlyEmptyBounds = tp.typeParams.forall(_.paramInfo == TypeBounds .empty)
46
42
onlyEmptyBounds
47
43
// Note: this pre-test helps efficiency. It is also necessary to workaround #9965 since in some cases
@@ -50,18 +46,24 @@ object TypeApplications {
50
46
// In this case, we can still return true if we know that the hk lambda bounds
51
47
// are empty anyway.
52
48
|| {
49
+ val tparams = fn.typeParams
53
50
val paramRefs = tparams.map(_.paramRef)
51
+ val prefix = fn.normalizedPrefix
52
+ val owner = fn.typeSymbol.maybeOwner
54
53
tp.typeParams.corresponds(tparams) { (param1, param2) =>
55
- param2.paramInfo frozen_<:< param1.paramInfo.substParams(tp, paramRefs)
54
+ // see tests/neg/variances-constr.scala
55
+ // its B parameter should have info <: Any, using class C as the owner
56
+ // rather than info <: A, using class Inner2 as the owner
57
+ param2.paramInfo.asSeenFrom(prefix, owner) frozen_<:< param1.paramInfo.substParams(tp, paramRefs)
56
58
}
57
59
}
58
60
59
61
def unapply (tp : Type )(using Context ): Option [Type ] = tp match
60
- case tp @ HKTypeLambda (tparams, AppliedType (fn : Type , args))
62
+ case tp @ HKTypeLambda (tparams, AppliedType (fn, args))
61
63
if fn.typeSymbol.isClass
62
64
&& tparams.hasSameLengthAs(args)
63
65
&& args.lazyZip(tparams).forall((arg, tparam) => arg == tparam.paramRef)
64
- && weakerBounds(tp, fn.typeParams ) => Some (fn)
66
+ && weakerBounds(tp, fn) => Some (fn)
65
67
case _ => None
66
68
67
69
end EtaExpansion
@@ -244,7 +246,7 @@ class TypeApplications(val self: Type) extends AnyVal {
244
246
def topType (using Context ): Type =
245
247
if self.hasSimpleKind then
246
248
defn.AnyType
247
- else etaExpand( self.typeParams) match
249
+ else self.etaExpand match
248
250
case tp : HKTypeLambda =>
249
251
tp.derivedLambdaType(resType = tp.resultType.topType)
250
252
case _ =>
@@ -301,21 +303,44 @@ class TypeApplications(val self: Type) extends AnyVal {
301
303
/** Convert a type constructor `TC` which has type parameters `X1, ..., Xn`
302
304
* to `[X1, ..., Xn] -> TC[X1, ..., Xn]`.
303
305
*/
304
- def etaExpand (tparams : List [TypeParamInfo ])(using Context ): Type =
305
- HKTypeLambda .fromParams(tparams, self.appliedTo(tparams.map(_.paramRef)))
306
- // .ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}")
306
+ def etaExpand (using Context ): Type =
307
+ val tparams = self.typeParams
308
+ val resType = self.appliedTo(tparams.map(_.paramRef))
309
+ self.dealias match
310
+ case self : TypeRef if tparams.nonEmpty && self.symbol.isClass =>
311
+ val owner = self.symbol.owner
312
+ // Calling asSeenFrom on the type parameter infos is important
313
+ // so that class type references within another prefix have
314
+ // their type parameters' info fixed.
315
+ // e.g. from pos/i18569:
316
+ // trait M1:
317
+ // trait A
318
+ // trait F[T <: A]
319
+ // object M2 extends M1
320
+ // Type parameter T in M1.F has an upper bound of M1#A
321
+ // But eta-expanding M2.F should have type parameters with an upper-bound of M2.A.
322
+ // So we take the prefix M2.type and the F symbol's owner, M1,
323
+ // to call asSeenFrom on T's info.
324
+ HKTypeLambda (tparams.map(_.paramName))(
325
+ tl => tparams.map(p => HKTypeLambda .toPInfo(tl.integrate(tparams, p.paramInfo.asSeenFrom(self.prefix, owner)))),
326
+ tl => tl.integrate(tparams, resType))
327
+ case _ =>
328
+ HKTypeLambda .fromParams(tparams, resType)
307
329
308
330
/** If self is not lambda-bound, eta expand it. */
309
331
def ensureLambdaSub (using Context ): Type =
310
- if (isLambdaSub) self else EtaExpansion (self)
332
+ if isLambdaSub then self
333
+ else
334
+ assert(self.typeParams.nonEmpty, self)
335
+ self.etaExpand
311
336
312
337
/** Eta expand if `self` is a (non-lambda) class reference and `bound` is a higher-kinded type */
313
338
def etaExpandIfHK (bound : Type )(using Context ): Type = {
314
339
val hkParams = bound.hkTypeParams
315
340
if (hkParams.isEmpty) self
316
341
else self match {
317
- case self : TypeRef if self.symbol.isClass && self.typeParams.length == hkParams.length =>
318
- EtaExpansion (self)
342
+ case self : TypeRef if self.symbol.isClass && self.typeParams.hasSameLengthAs( hkParams) =>
343
+ etaExpand
319
344
case _ => self
320
345
}
321
346
}
0 commit comments