From bd67c201c8ee4be3182ebc65f0f4f55c2296029c Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Thu, 24 Dec 2020 13:38:23 +0200 Subject: [PATCH] Fix checkKindBoundsHK for higher kinds We need to flip the direction of the checks on every other level. This is similar to contravariance of higher-order function types. --- .../scala/reflect/internal/Kinds.scala | 16 +++++++++----- test/files/neg/subkinding.check | 16 ++++++++++++++ test/files/neg/subkinding.scala | 21 +++++++++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 test/files/neg/subkinding.check create mode 100644 test/files/neg/subkinding.scala diff --git a/src/reflect/scala/reflect/internal/Kinds.scala b/src/reflect/scala/reflect/internal/Kinds.scala index ff40f563ace8..698be6563c5c 100644 --- a/src/reflect/scala/reflect/internal/Kinds.scala +++ b/src/reflect/scala/reflect/internal/Kinds.scala @@ -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 @@ -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) @@ -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 + @@ -200,7 +204,8 @@ trait Kinds { hkparam, paramOwner, underHKParams ++ hkparam.typeParams, - withHKArgs ++ hkarg.typeParams + withHKArgs ++ hkarg.typeParams, + !flip ) } if (!explainErrors && !kindErrors.isEmpty) @@ -228,7 +233,8 @@ trait Kinds { if (targ.isHigherKinded || tparam.typeParams.nonEmpty) { val kindErrors = checkKindBoundsHK( tparamsHO, targSym, targPre, 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)) diff --git a/test/files/neg/subkinding.check b/test/files/neg/subkinding.check new file mode 100644 index 000000000000..6e2179ab7bd0 --- /dev/null +++ b/test/files/neg/subkinding.check @@ -0,0 +1,16 @@ +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] + ^ +subkinding.scala:20: error: kinds of the type arguments (Test3.Adapter,T) do not conform to the expected kinds of the type parameters (type A,type S) in trait Mixin. +Test3.Adapter's type parameters do not match type A's expected parameters: +type B (in trait Adapter)'s bounds <: Test3.Box[T] are stricter than type B's declared bounds <: Test3.Box[S] + trait Super[T] extends Mixin[Adapter, T] + ^ +3 errors diff --git a/test/files/neg/subkinding.scala b/test/files/neg/subkinding.scala new file mode 100644 index 000000000000..5a1745e8c535 --- /dev/null +++ b/test/files/neg/subkinding.scala @@ -0,0 +1,21 @@ +// scala/bug#2067 +object Test1 { + trait A[B[D[X, Y <: X]]] + trait C[E[T, S]] + type T = A[C] +} + +// scala/bug#2067 +object Test2 { + trait A[T[_[_]]] + trait C[X[+_]] + type T = A[C] +} + +// scala/bug#12242 +object Test3 { + trait Box[T] + trait Adapter[B <: Box[T], T] + trait Mixin[+A[B <: Box[S], X], S] + trait Super[T] extends Mixin[Adapter, T] +}