diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index d88b0df2bede..a55434c54bd0 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -341,8 +341,21 @@ object desugar { (if (args.isEmpty) tycon else AppliedTypeTree(tycon, args)) .withPos(cdef.pos.startPos) - def appliedRef(tycon: Tree, tparams: List[TypeDef] = constrTparams) = - appliedTypeTree(tycon, tparams map refOfDef) + def appliedRef(tycon: Tree, tparams: List[TypeDef] = constrTparams, widenHK: Boolean = false) = { + val targs = for (tparam <- tparams) yield { + val targ = refOfDef(tparam) + def fullyApplied(tparam: Tree): Tree = tparam match { + case TypeDef(_, LambdaTypeTree(tparams, body)) => + AppliedTypeTree(targ, tparams.map(_ => TypeBoundsTree(EmptyTree, EmptyTree))) + case TypeDef(_, rhs: DerivedTypeTree) => + fullyApplied(rhs.watched) + case _ => + targ + } + if (widenHK) fullyApplied(tparam) else targ + } + appliedTypeTree(tycon, targs) + } // a reference to the class type bound by `cdef`, with type parameters coming from the constructor val classTypeRef = appliedRef(classTycon) @@ -431,12 +444,16 @@ object desugar { // // implicit def eqInstance[T1$1, ..., Tn$1, T1$2, ..., Tn$2](implicit // ev1: Eq[T1$1, T1$2], ..., evn: Eq[Tn$1, Tn$2]]) - // : Eq[C[T1$1, ..., Tn$1], C[T1$2, ..., Tn$2]] = Eq + // : Eq[C[T1$, ..., Tn$1], C[T1$2, ..., Tn$2]] = Eq + // + // If any of the T_i are higher-kinded, say `Ti[X1 >: L1 <: U1, ..., Xm >: Lm <: Um]`, + // the corresponding type parameters for $ev_i are `Ti$1[_, ..., _], Ti$2[_, ..., _]` + // (with m underscores `_`). def eqInstance = { val leftParams = constrTparams.map(derivedTypeParam(_, "$1")) val rightParams = constrTparams.map(derivedTypeParam(_, "$2")) val subInstances = (leftParams, rightParams).zipped.map((param1, param2) => - appliedRef(ref(defn.EqType), List(param1, param2))) + appliedRef(ref(defn.EqType), List(param1, param2), widenHK = true)) DefDef( name = nme.eqInstance, tparams = leftParams ++ rightParams, diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e7f3acf4d033..4238cbfc1359 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1754,21 +1754,25 @@ object Types { val idx = typeParams.indexOf(param) - assert(args.nonEmpty, - i"""bad parameter reference $this at ${ctx.phase} - |the parameter is ${param.showLocated} but the prefix $prefix - |does not define any corresponding arguments.""") - - val argInfo = args(idx) match { - case arg: TypeBounds => - val v = param.paramVariance - val pbounds = param.paramInfo - if (v > 0 && pbounds.loBound.dealias.isBottomType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound)) - else if (v < 0 && pbounds.hiBound.dealias.isTopType) TypeAlias(arg.loBound | rebase(pbounds.loBound)) - else arg recoverable_& rebase(pbounds) - case arg => TypeAlias(arg) + if (idx < args.length) { + val argInfo = args(idx) match { + case arg: TypeBounds => + val v = param.paramVariance + val pbounds = param.paramInfo + if (v > 0 && pbounds.loBound.dealias.isBottomType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound)) + else if (v < 0 && pbounds.hiBound.dealias.isTopType) TypeAlias(arg.loBound | rebase(pbounds.loBound)) + else arg recoverable_& rebase(pbounds) + case arg => TypeAlias(arg) + } + param.derivedSingleDenotation(param, argInfo) + } + else { + assert(ctx.reporter.errorsReported, + i"""bad parameter reference $this at ${ctx.phase} + |the parameter is ${param.showLocated} but the prefix $prefix + |does not define any corresponding arguments.""") + NoDenotation } - param.derivedSingleDenotation(param, argInfo) } /** Reload denotation by computing the member with the reference's name as seen diff --git a/tests/neg/i3976.scala b/tests/neg/i3976.scala new file mode 100644 index 000000000000..9462ce583fa6 --- /dev/null +++ b/tests/neg/i3976.scala @@ -0,0 +1,58 @@ +object Test { + enum Hoge[F[_]] { + case A extends Hoge[List] + case B extends Hoge[[X] => String] + } + import Hoge._ + + A == A + A == (B: Hoge[_]) + + A == B // error: cannot be compared + + class C + + A == "" // error: cannot be compared + A == new C // error: cannot be compared + +} + +object Test2 { + enum Hoge[F[G[_]]] { + case A extends Hoge[[F[_]] => F[Int]] + case B extends Hoge[[F[_]] => F[String]] + } + import Hoge._ + + A == A + A == (B: Hoge[_]) + + A == B + + class C + + A == "" // error: cannot be compared + A == new C // error: cannot be compared + +} + +object Test3 { + enum Hoge[F[G[_]]] { + case A extends Hoge[[X] => List] // error: wrong kind + case B extends Hoge[[X] => [Y] => String] // error: wrong kind + } + import Hoge._ + + A == A + A == (B: Hoge[_]) + + A == B + + class C + + A == "" + A == new C + +} + + diff --git a/tests/pos/i3976.scala b/tests/pos/i3976.scala new file mode 100644 index 000000000000..03ae4bb146cf --- /dev/null +++ b/tests/pos/i3976.scala @@ -0,0 +1,10 @@ +object Test { + enum Hoge[F[_]] { + case A extends Hoge[List] + case B extends Hoge[[X] => String] + } + import Hoge._ + + A == A + A == (B: Hoge[_]) +}