Skip to content

Commit

Permalink
Collapse into 1 etaExpand (to rule them all)
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Nov 28, 2023
1 parent 6428333 commit 357aa08
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 38 deletions.
62 changes: 31 additions & 31 deletions compiler/src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ object TypeApplications {
*/
object EtaExpansion:

def apply(tycon: Type)(using Context): Type =
assert(tycon.typeParams.nonEmpty, tycon)
tycon.etaExpand(tycon.typeParamSymbols)

/** Test that the parameter bounds in a hk type lambda `[X1,...,Xn] => C[X1, ..., Xn]`
* contain the bounds of the type parameters of `C`. This is necessary to be able to
* contract the hk lambda to `C`.
Expand Down Expand Up @@ -245,7 +241,7 @@ class TypeApplications(val self: Type) extends AnyVal {
def topType(using Context): Type =
if self.hasSimpleKind then
defn.AnyType
else etaExpand(self.typeParams) match
else self.etaExpand match
case tp: HKTypeLambda =>
tp.derivedLambdaType(resType = tp.resultType.topType)
case _ =>
Expand Down Expand Up @@ -302,45 +298,49 @@ class TypeApplications(val self: Type) extends AnyVal {
/** Convert a type constructor `TC` which has type parameters `X1, ..., Xn`
* to `[X1, ..., Xn] -> TC[X1, ..., Xn]`.
*/
def etaExpand(tparams: List[TypeParamInfo])(using Context): Type =
HKTypeLambda.fromParams(tparams, self.appliedTo(tparams.map(_.paramRef)))
//.ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}")
def etaExpand(using Context): Type =
val tparams = self.typeParams
val resType = self.appliedTo(tparams.map(_.paramRef))
self match
case self: TypeRef if tparams.nonEmpty && self.symbol.isClass =>
val prefix = self.prefix
val owner = self.symbol.owner
// Calling asSeenFrom on the type parameter infos is important
// so that class type references within another prefix have
// their type parameters' info fixed.
// e.g. from pos/i18569:
// trait M1:
// trait A
// trait F[T <: A]
// object M2 extends M1
// Type parameter T in M1.F has an upper bound of M1#A
// But eta-expanding M2.F should have type parameters with an upper-bound of M2.A.
// So we take the prefix M2.type and the F symbol's owner, M1,
// to call asSeenFrom on T's info.
HKTypeLambda(tparams.map(_.paramName))(
tl => tparams.map(p => HKTypeLambda.toPInfo(tl.integrate(tparams, p.paramInfo.asSeenFrom(prefix, owner)))),
tl => tl.integrate(tparams, resType))
case _ =>
HKTypeLambda.fromParams(tparams, resType)

/** If self is not lambda-bound, eta expand it. */
def ensureLambdaSub(using Context): Type =
if (isLambdaSub) self else EtaExpansion(self)
if isLambdaSub then self
else
assert(self.typeParams.nonEmpty, self)
self.etaExpand

/** Eta expand if `self` is a (non-lambda) class reference and `bound` is a higher-kinded type */
def etaExpandIfHK(bound: Type)(using Context): Type = {
val hkParams = bound.hkTypeParams
if (hkParams.isEmpty) self
else self match {
case self: TypeRef if self.symbol.isClass && self.typeParams.length == hkParams.length =>
EtaExpansion(self)
case self: TypeRef if self.symbol.isClass && self.typeParams.hasSameLengthAs(hkParams) =>
etaExpand
case _ => self
}
}

// Like `target.etaExpand(target.typeParams)`
// except call `asSeenFrom` to fix class type parameter bounds
// e.g. from pos/i18569:
// trait M1:
// trait A
// trait F[T <: A]
// object M2 extends M1
// Type parameter T in M2.F has an upper bound of M1#A instead of M2.A
// So we take the prefix M2.type and the F symbol's owner, M1,
// to call asSeenFrom on T's info.
def etaExpandWithAsf(using Context): Type = self match
case self: TypeRef if self.symbol.isClass =>
val tparams = self.symbol.typeParams
val prefix = self.prefix
val owner = self.symbol.owner
HKTypeLambda(tparams.map(_.paramName))(
tl => tparams.map(p => HKTypeLambda.toPInfo(tl.integrate(tparams, p.info.asSeenFrom(prefix, owner)))),
tl => tl.integrate(tparams, self.appliedTo(tparams.map(_.paramRef))))
case _ => etaExpand(typeParams)

/** Maps [Ts] => C[Ts] to C */
def etaCollapse(using Context): Type = self match
case EtaExpansion(classType) => classType
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
if (base.typeSymbol == cls2) return true
}
else if tp1.typeParams.nonEmpty && !tp1.isAnyKind then
return recur(tp1, EtaExpansion(tp2))
return recur(tp1, tp2.etaExpand)
fourthTry
}

Expand Down Expand Up @@ -746,7 +746,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
case _ =>
val tparams1 = tp1.typeParams
if (tparams1.nonEmpty)
return recur(tp1.etaExpand(tparams1), tp2) || fourthTry
return recur(tp1.etaExpand, tp2) || fourthTry
tp2 match {
case EtaExpansion(tycon2: TypeRef) if tycon2.symbol.isClass && tycon2.symbol.is(JavaDefined) =>
recur(tp1, tycon2) || fourthTry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
}
else if args.nonEmpty then
tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly)))
else if (sym.typeParams.nonEmpty) tycon.etaExpand(sym.typeParams)
else if (sym.typeParams.nonEmpty) tycon.etaExpand
else tycon
case TYPEBOUNDStpe =>
val lo = readTypeRef()
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Deriving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ trait Deriving {
// case (a) ... see description above
val derivedParams = clsParams.dropRight(instanceArity)
val instanceType =
if (instanceArity == clsArity) clsType.etaExpand(clsParams)
if (instanceArity == clsArity) clsType.etaExpand
else {
val derivedParamTypes = derivedParams.map(_.typeRef)

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@ class Namer { typer: Typer =>
val forwarderName = checkNoConflict(alias.toTypeName, isPrivate = false, span)
var target = pathType.select(sym)
if target.typeParams.nonEmpty then
target = target.etaExpandWithAsf
target = target.etaExpand
newSymbol(
cls, forwarderName,
Exported | Final,
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ object RefChecks {
*/
def checkOverride(checkSubType: (Type, Type) => Context ?=> Boolean, member: Symbol, other: Symbol): Unit =
def memberTp(self: Type) =
if (member.isClass) TypeAlias(member.typeRef.etaExpand(member.typeParams))
if (member.isClass) TypeAlias(member.typeRef.etaExpand)
else self.memberInfo(member)
def otherTp(self: Type) =
self.memberInfo(other)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4306,7 +4306,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
AppliedType(tree.tpe, tp.typeParams.map(Function.const(TypeBounds.empty)))
else
// Eta-expand higher-kinded type
tree.tpe.etaExpand(tp.typeParamSymbols)
tree.tpe.etaExpand
tree.withType(tp1)
}
if (ctx.mode.is(Mode.Pattern) || ctx.mode.isQuotedPattern || tree1.tpe <:< pt) tree1
Expand Down

0 comments on commit 357aa08

Please sign in to comment.