From 49962b2181f764c92fb9e69fe8fb687627592675 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 11 Nov 2024 14:02:32 +0000 Subject: [PATCH] Fix HK type param bounds variance checking --- .../tools/dotc/printing/Formatting.scala | 4 ++ .../tools/dotc/typer/VarianceChecker.scala | 10 ++- tests/neg/i21625.check | 72 +++++++++++++++++++ tests/neg/i21625.scala | 60 ++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i21625.check create mode 100644 tests/neg/i21625.scala diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index 5870731dadfa..656b744a1077 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -87,6 +87,10 @@ object Formatting { def show(x: H *: T) = CtxShow(toStr(x.head) *: toShown(x.tail).asInstanceOf[Tuple]) + given Show[typer.VarianceChecker.VarianceError] with + def show(x: typer.VarianceChecker.VarianceError) = + CtxShow("VarianceError(" + toStr(x.tvar) + ", " + toStr(x.required) + ")") + given Show[FlagSet] with def show(x: FlagSet) = x.flagsString diff --git a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala index 3699ca80d011..ebdd5b84dcbb 100644 --- a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -120,7 +120,7 @@ class VarianceChecker(using Context) { * explicitly (their TypeDefs will be passed here.) For MethodTypes, the * same is true of the parameters (ValDefs). */ - def apply(status: Option[VarianceError], tp: Type): Option[VarianceError] = trace(s"variance checking $tp of $base at $variance", variances) { + def apply(status: Option[VarianceError], tp: Type): Option[VarianceError] = trace(i"variance checking $tp of $base at $variance", variances) { try if (status.isDefined) status else tp match { @@ -136,6 +136,14 @@ class VarianceChecker(using Context) { status case tp: ClassInfo => foldOver(status, tp.parents) + case tp @ TypeBounds(lo: LambdaType, hi) if lo ne hi => + // When checking the info of higher-kinded type members, + // (such as the following from i21625) + // type F_NL_LB[M <: L] >: LB[M] + // we only check the lambda type param bounds (`>: L`) + // when checking the upper bound, eg `<: [M <: L] =>> Any`, + // not when checking the lower bound `>: [M <: L] =>> LB[M]`. + foldOver(status, tp.derivedTypeBounds(lo.resultType, hi)) case _ => foldOver(status, tp) } diff --git a/tests/neg/i21625.check b/tests/neg/i21625.check new file mode 100644 index 000000000000..05438721e558 --- /dev/null +++ b/tests/neg/i21625.check @@ -0,0 +1,72 @@ +-- Error: tests/neg/i21625.scala:5:7 ----------------------------------------------------------------------------------- +5 | type F_LA_LB[K >: L] >: LB[K] // error: >: L + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | contravariant type L occurs in covariant position in type [K >: L] >: LB[K] of type F_LA_LB +-- Error: tests/neg/i21625.scala:8:7 ----------------------------------------------------------------------------------- +8 | type F_NU_LB[V <: U] >: LB[V] // error: <: U + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | covariant type U occurs in contravariant position in type [V <: U] >: LB[V] of type F_NU_LB +-- Error: tests/neg/i21625.scala:10:7 ---------------------------------------------------------------------------------- +10 | type F_LA_UB[K >: L] <: UB[K] // error: >: L + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | contravariant type L occurs in covariant position in type [K >: L] <: UB[K] of type F_LA_UB +-- Error: tests/neg/i21625.scala:13:7 ---------------------------------------------------------------------------------- +13 | type F_NU_UB[V <: U] <: UB[V] // error: <: U + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | covariant type U occurs in contravariant position in type [V <: U] <: UB[V] of type F_NU_UB +-- Error: tests/neg/i21625.scala:17:7 ---------------------------------------------------------------------------------- +17 | F_NL_LB[M <: L] >: LB[M], // error: <: L + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | contravariant type L occurs in covariant position in type [M <: L] >: LB[M] of type F_NL_LB +-- Error: tests/neg/i21625.scala:18:7 ---------------------------------------------------------------------------------- +18 | F_UA_LB[T >: U] >: LB[T], // error: >: U + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | covariant type U occurs in contravariant position in type [T >: U] >: LB[T] of type F_UA_LB +-- Error: tests/neg/i21625.scala:22:7 ---------------------------------------------------------------------------------- +22 | F_NL_UB[M <: L] <: UB[M], // error: <: L + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | contravariant type L occurs in covariant position in type [M <: L] <: UB[M] of type F_NL_UB +-- Error: tests/neg/i21625.scala:23:7 ---------------------------------------------------------------------------------- +23 | F_UA_UB[T >: U] <: UB[T], // error: >: U + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | covariant type U occurs in contravariant position in type [T >: U] <: UB[T] of type F_UA_UB +-- Error: tests/neg/i21625.scala:28:7 ---------------------------------------------------------------------------------- +28 | type M <: L // error: <: L + | ^^^^^^^^^^^ + | contravariant type L occurs in covariant position in type <: L of type M +-- Error: tests/neg/i21625.scala:29:7 ---------------------------------------------------------------------------------- +29 | type T >: U // error: >: U + | ^^^^^^^^^^^ + | covariant type U occurs in contravariant position in type >: U of type T +-- Error: tests/neg/i21625.scala:32:10 --------------------------------------------------------------------------------- +32 | def d_K[K >: L](): K // error: >: L + | ^^^^^^ + | contravariant type L occurs in covariant position in type >: L of type K +-- Error: tests/neg/i21625.scala:33:6 ---------------------------------------------------------------------------------- +33 | def d_L(): L // error: => L + | ^^^^^^^^^^^^^^^^^^^^ + | contravariant type L occurs in covariant position in type (): L of method d_L +-- Error: tests/neg/i21625.scala:37:10 --------------------------------------------------------------------------------- +37 | def d_V[V <: U](): V // error: <: U + | ^^^^^^ + | covariant type U occurs in contravariant position in type <: U of type V +-- Error: tests/neg/i21625.scala:40:6 ---------------------------------------------------------------------------------- +40 | val v_L: L // error: L + | ^^^^^^^^^^ + | contravariant type L occurs in covariant position in type L of value v_L +-- Error: tests/neg/i21625.scala:48:15 --------------------------------------------------------------------------------- +48 | def d_K_Unit[K >: L](): K => Unit // error: >: L + | ^^^^^^ + | contravariant type L occurs in covariant position in type >: L of type K +-- Error: tests/neg/i21625.scala:52:6 ---------------------------------------------------------------------------------- +52 | def d_U_Unit(): U => Unit // error: U => + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | covariant type U occurs in contravariant position in type (): U => Unit of method d_U_Unit +-- Error: tests/neg/i21625.scala:53:15 --------------------------------------------------------------------------------- +53 | def d_V_Unit[V <: U](): V => Unit // error: <: U + | ^^^^^^ + | covariant type U occurs in contravariant position in type <: U of type V +-- Error: tests/neg/i21625.scala:59:6 ---------------------------------------------------------------------------------- +59 | val v_U_Unit: U => Unit // error: U => + | ^^^^^^^^^^^^^^^^^^^^^^^ + | covariant type U occurs in contravariant position in type U => Unit of value v_U_Unit diff --git a/tests/neg/i21625.scala b/tests/neg/i21625.scala new file mode 100644 index 000000000000..6e4ec403a345 --- /dev/null +++ b/tests/neg/i21625.scala @@ -0,0 +1,60 @@ +trait LB[X]; trait UB[Y] + +trait Foo[-L, +U]: + + type F_LA_LB[K >: L] >: LB[K] // error: >: L + type F_NL_LB[M <: L] >: LB[M] // was: error: <: L + type F_UA_LB[T >: U] >: LB[T] // was: error: >: U + type F_NU_LB[V <: U] >: LB[V] // error: <: U + + type F_LA_UB[K >: L] <: UB[K] // error: >: L + type F_NL_UB[M <: L] <: UB[M] + type F_UA_UB[T >: U] <: UB[T] + type F_NU_UB[V <: U] <: UB[V] // error: <: U + + def hk[ + F_LA_LB[K >: L] >: LB[K], // was: error: >: L + F_NL_LB[M <: L] >: LB[M], // error: <: L + F_UA_LB[T >: U] >: LB[T], // error: >: U + F_NU_LB[V <: U] >: LB[V], // was: error: <: U + + F_LA_UB[K >: L] <: UB[K], + F_NL_UB[M <: L] <: UB[M], // error: <: L + F_UA_UB[T >: U] <: UB[T], // error: >: U + F_NU_UB[V <: U] <: UB[V], + ]: Unit + + type K >: L + type M <: L // error: <: L + type T >: U // error: >: U + type V <: U + + def d_K[K >: L](): K // error: >: L + def d_L(): L // error: => L + def d_M[M <: L](): M + def d_T[T >: U](): T + def d_U(): U + def d_V[V <: U](): V // error: <: U + + val v_K: K + val v_L: L // error: L + val v_M: M // indirect error: M <: L + val v_T: T // indirect error: T >: U + val v_U: U + val v_V: V + + // reverse + + def d_K_Unit[K >: L](): K => Unit // error: >: L + def d_L_Unit(): L => Unit + def d_M_Unit[M <: L](): M => Unit + def d_T_Unit[T >: U](): T => Unit + def d_U_Unit(): U => Unit // error: U => + def d_V_Unit[V <: U](): V => Unit // error: <: U + + val v_K_Unit: K => Unit + val v_L_Unit: L => Unit + val v_M_Unit: M => Unit + val v_T_Unit: T => Unit + val v_U_Unit: U => Unit // error: U => + val v_V_Unit: V => Unit