Skip to content

Commit

Permalink
Fix checkKindBoundsHK for higher kinds
Browse files Browse the repository at this point in the history
We need to flip the direction of the checks on every other level.
This is similar to contravariance of higher-order function types.
  • Loading branch information
joroKr21 committed Dec 24, 2020
1 parent 1851c5d commit 22fc021
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/reflect/scala/reflect/internal/Kinds.scala
Expand Up @@ -140,7 +140,8 @@ trait Kinds {
param: Symbol,
paramOwner: Symbol,
underHKParams: List[Symbol],
withHKArgs: List[Symbol]
withHKArgs: List[Symbol],
flip: Boolean
): KindErrors = {

var kindErrors: KindErrors = NoKindErrors
Expand All @@ -165,7 +166,9 @@ trait Kinds {
}
else foreach2(hkargs, hkparams) { (hkarg, hkparam) =>
if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind *
kindCheck(variancesMatch(hkarg, hkparam), _.varianceError(hkarg -> hkparam))
if (flip) kindCheck(variancesMatch(hkparam, hkarg), _.varianceError(hkparam -> hkarg))
else kindCheck(variancesMatch(hkarg, hkparam), _.varianceError(hkarg -> hkparam))

// instantiateTypeParams(tparams, targs)
// higher-order bounds, may contain references to type arguments
// substSym(hkparams, hkargs)
Expand All @@ -179,7 +182,8 @@ trait Kinds {
val declaredBoundsInst = declaredBounds.substSym(underHKParams, withHKArgs).asSeenFrom(pre, owner)
val argumentBounds = hkarg.info.bounds.asSeenFrom(argPre, argOwner).asSeenFrom(pre, owner)

kindCheck(declaredBoundsInst <:< argumentBounds, _.strictnessError(hkarg -> hkparam))
if (flip) kindCheck(argumentBounds <:< declaredBoundsInst, _.strictnessError(hkparam -> hkarg))
else kindCheck(declaredBoundsInst <:< argumentBounds, _.strictnessError(hkarg -> hkparam))

debuglog(
"checkKindBoundsHK base case: " + hkparam +
Expand All @@ -200,7 +204,8 @@ trait Kinds {
hkparam,
paramOwner,
underHKParams ++ hkparam.typeParams,
withHKArgs ++ hkarg.typeParams
withHKArgs ++ hkarg.typeParams,
!flip
)
}
if (!explainErrors && !kindErrors.isEmpty)
Expand All @@ -227,7 +232,8 @@ trait Kinds {
if (targ.isHigherKinded || tparam.typeParams.nonEmpty) {
val kindErrors = checkKindBoundsHK(
tparamsHO, targSym, targ.prefix, targSym.owner,
tparam, tparam.owner, tparam.typeParams, tparamsHO
tparam, tparam.owner, tparam.typeParams, tparamsHO,
flip = false
)
if (kindErrors.isEmpty) Nil else {
if (explainErrors) List((targ, tparam, kindErrors))
Expand Down
11 changes: 11 additions & 0 deletions test/files/neg/subkinding.check
@@ -0,0 +1,11 @@
subkinding.scala:5: error: kinds of the type arguments (Test1.C) do not conform to the expected kinds of the type parameters (type B) in trait A.
Test1.C's type parameters do not match type B's expected parameters:
type Y's bounds <: X are stricter than type S's declared bounds >: Nothing <: Any
type T = A[C]
^
subkinding.scala:12: error: kinds of the type arguments (Test2.C) do not conform to the expected kinds of the type parameters (type T) in trait A.
Test2.C's type parameters do not match type T's expected parameters:
type _ is invariant, but type _ is declared covariant
type T = A[C]
^
2 errors
13 changes: 13 additions & 0 deletions test/files/neg/subkinding.scala
@@ -0,0 +1,13 @@
object Test1 {
trait A[B[D[X, Y <: X]]]
trait C[E[T, S]]
trait P[U, V <: U]
type T = A[C]
}

object Test2 {
class P[Y](val y : Y)
trait A[T[_[_]]]
trait C[X[+_]]
type T = A[C]
}

0 comments on commit 22fc021

Please sign in to comment.