@@ -33,15 +33,11 @@ object TypeApplications {
3333 */
3434 object EtaExpansion :
3535
36- def apply (tycon : Type )(using Context ): Type =
37- assert(tycon.typeParams.nonEmpty, tycon)
38- tycon.etaExpand(tycon.typeParamSymbols)
39-
4036 /** Test that the parameter bounds in a hk type lambda `[X1,...,Xn] => C[X1, ..., Xn]`
4137 * contain the bounds of the type parameters of `C`. This is necessary to be able to
4238 * contract the hk lambda to `C`.
4339 */
44- private def weakerBounds (tp : HKTypeLambda , tparams : List [ ParamInfo ] )(using Context ): Boolean =
40+ private def weakerBounds (tp : HKTypeLambda , fn : Type )(using Context ): Boolean =
4541 val onlyEmptyBounds = tp.typeParams.forall(_.paramInfo == TypeBounds .empty)
4642 onlyEmptyBounds
4743 // Note: this pre-test helps efficiency. It is also necessary to workaround #9965 since in some cases
@@ -50,18 +46,24 @@ object TypeApplications {
5046 // In this case, we can still return true if we know that the hk lambda bounds
5147 // are empty anyway.
5248 || {
49+ val tparams = fn.typeParams
5350 val paramRefs = tparams.map(_.paramRef)
51+ val prefix = fn.normalizedPrefix
52+ val owner = fn.typeSymbol.maybeOwner
5453 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)
5658 }
5759 }
5860
5961 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))
6163 if fn.typeSymbol.isClass
6264 && tparams.hasSameLengthAs(args)
6365 && args.lazyZip(tparams).forall((arg, tparam) => arg == tparam.paramRef)
64- && weakerBounds(tp, fn.typeParams ) => Some (fn)
66+ && weakerBounds(tp, fn) => Some (fn)
6567 case _ => None
6668
6769 end EtaExpansion
@@ -244,7 +246,7 @@ class TypeApplications(val self: Type) extends AnyVal {
244246 def topType (using Context ): Type =
245247 if self.hasSimpleKind then
246248 defn.AnyType
247- else etaExpand( self.typeParams) match
249+ else self.etaExpand match
248250 case tp : HKTypeLambda =>
249251 tp.derivedLambdaType(resType = tp.resultType.topType)
250252 case _ =>
@@ -301,21 +303,44 @@ class TypeApplications(val self: Type) extends AnyVal {
301303 /** Convert a type constructor `TC` which has type parameters `X1, ..., Xn`
302304 * to `[X1, ..., Xn] -> TC[X1, ..., Xn]`.
303305 */
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)
307329
308330 /** If self is not lambda-bound, eta expand it. */
309331 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
311336
312337 /** Eta expand if `self` is a (non-lambda) class reference and `bound` is a higher-kinded type */
313338 def etaExpandIfHK (bound : Type )(using Context ): Type = {
314339 val hkParams = bound.hkTypeParams
315340 if (hkParams.isEmpty) self
316341 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
319344 case _ => self
320345 }
321346 }
0 commit comments