Skip to content

Commit c2d8fa6

Browse files
committed
Fix desugaring of higher-kinded enums
This previous encoding used a higher-kinded type applied to a wildcard argument, which is no longer supported. The new encoding is a temporary fix. To get it right, it's best if we can base it on the future typeclass derivation mechanism.
1 parent 1d04427 commit c2d8fa6

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,12 @@ object desugar {
366366
(if (args.isEmpty) tycon else AppliedTypeTree(tycon, args))
367367
.withPos(cdef.pos.startPos)
368368

369+
def isHK(tparam: Tree): Boolean = tparam match {
370+
case TypeDef(_, LambdaTypeTree(tparams, body)) => true
371+
case TypeDef(_, rhs: DerivedTypeTree) => isHK(rhs.watched)
372+
case _ => false
373+
}
374+
369375
def appliedRef(tycon: Tree, tparams: List[TypeDef] = constrTparams, widenHK: Boolean = false) = {
370376
val targs = for (tparam <- tparams) yield {
371377
val targ = refOfDef(tparam)
@@ -467,18 +473,29 @@ object desugar {
467473
// ev1: Eq[T1$1, T1$2], ..., evn: Eq[Tn$1, Tn$2]])
468474
// : Eq[C[T1$, ..., Tn$1], C[T1$2, ..., Tn$2]] = Eq
469475
//
470-
// If any of the T_i are higher-kinded, say `Ti[X1 >: L1 <: U1, ..., Xm >: Lm <: Um]`,
471-
// the corresponding type parameters for $ev_i are `Ti$1[_, ..., _], Ti$2[_, ..., _]`
472-
// (with m underscores `_`).
476+
// Higher-kinded type arguments `Ti` are omitted as evidence parameters.
477+
//
478+
// FIXME: This is too simplistic. Instead of just generating evidence arguments
479+
// for every first-kinded type parameter, we should look instead at the
480+
// actual types occurring in cases and derive parameters from these. E.g. in
481+
//
482+
// enum HK[F[_]] {
483+
// case C1(x: F[Int]) extends HK[F[Int]]
484+
// case C2(y: F[String]) extends HL[F[Int]]
485+
//
486+
// we would need evidence parameters for `F[Int]` and `F[String]`
487+
// We should generate Eq instances with the techniques
488+
// of typeclass derivation once that is available.
473489
def eqInstance = {
474490
val leftParams = constrTparams.map(derivedTypeParam(_, "$1"))
475491
val rightParams = constrTparams.map(derivedTypeParam(_, "$2"))
476-
val subInstances = (leftParams, rightParams).zipped.map((param1, param2) =>
477-
appliedRef(ref(defn.EqType), List(param1, param2), widenHK = true))
492+
val subInstances =
493+
for ((param1, param2) <- leftParams `zip` rightParams if !isHK(param1))
494+
yield appliedRef(ref(defn.EqType), List(param1, param2), widenHK = true)
478495
DefDef(
479496
name = nme.eqInstance,
480497
tparams = leftParams ++ rightParams,
481-
vparamss = List(makeImplicitParameters(subInstances)),
498+
vparamss = if (subInstances.isEmpty) Nil else List(makeImplicitParameters(subInstances)),
482499
tpt = appliedTypeTree(ref(defn.EqType),
483500
appliedRef(classTycon, leftParams) :: appliedRef(classTycon, rightParams) :: Nil),
484501
rhs = ref(defn.EqModule.termRef)).withFlags(Synthetic | Implicit)

tests/neg/i3976.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ object Test {
88
A == A
99
A == (B: Hoge[_])
1010

11-
A == B // error: cannot be compared
11+
A == B // should be error: cannot be compared, needs proper typeclass drivation of `Eq` to get there.
1212

1313
class C
1414

0 commit comments

Comments
 (0)