diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-01-13 10:45:38 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-01-13 10:45:38 -0800 |
commit | 34c8a00da7a14803a7f38927ba11926561b2a188 (patch) | |
tree | db89325af094b4bdd9df7f6e0f57df898711dded | |
parent | 0a43c263568760ad291cbc76a98e1eb2de9292a7 (diff) | |
parent | 28d3390e07715b0dcb5ce2f68d72d5a44e6ca74d (diff) | |
download | scala-34c8a00da7a14803a7f38927ba11926561b2a188.tar.gz scala-34c8a00da7a14803a7f38927ba11926561b2a188.tar.bz2 scala-34c8a00da7a14803a7f38927ba11926561b2a188.zip |
Merge pull request #3184 from retronym/ticket/2066
SI-2066 Plug a soundness hole higher order type params, overriding
-rw-r--r-- | src/reflect/scala/reflect/internal/tpe/TypeComparers.scala | 16 | ||||
-rw-r--r-- | test/files/neg/t2066.check | 21 | ||||
-rw-r--r-- | test/files/neg/t2066.scala | 70 | ||||
-rw-r--r-- | test/files/neg/t2066b.check | 5 | ||||
-rw-r--r-- | test/files/neg/t2066b.scala (renamed from test/pending/neg/t2066.scala) | 0 | ||||
-rw-r--r-- | test/files/pos/t2066.scala | 25 |
6 files changed, 135 insertions, 2 deletions
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index b60fecd66e..2623a47be6 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -170,11 +170,20 @@ trait TypeComparers { // corresponds does not check length of two sequences before checking the predicate, // but SubstMap assumes it has been checked (SI-2956) ( sameLength(tparams1, tparams2) - && (tparams1 corresponds tparams2)((p1, p2) => p1.info =:= subst(p2.info)) + && (tparams1 corresponds tparams2)((p1, p2) => methodHigherOrderTypeParamsSameVariance(p1, p2) && p1.info =:= subst(p2.info)) && (res1 =:= subst(res2)) ) } + // SI-2066 This prevents overrides with incompatible variance in higher order type parameters. + private def methodHigherOrderTypeParamsSameVariance(sym1: Symbol, sym2: Symbol) = { + def ignoreVariance(sym: Symbol) = !(sym.isHigherOrderTypeParameter && sym.logicallyEnclosingMember.isMethod) + ignoreVariance(sym1) || ignoreVariance(sym2) || sym1.variance == sym2.variance + } + + private def methodHigherOrderTypeParamsSubVariance(low: Symbol, high: Symbol) = + methodHigherOrderTypeParamsSameVariance(low, high) || low.variance.isInvariant + def isSameType2(tp1: Type, tp2: Type): Boolean = { def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSameType(lhs, rhs) @@ -327,7 +336,10 @@ trait TypeComparers { val substitutes = if (isMethod) tparams1 else cloneSymbols(tparams1) def sub1(tp: Type) = if (isMethod) tp else tp.substSym(tparams1, substitutes) def sub2(tp: Type) = tp.substSym(tparams2, substitutes) - def cmp(p1: Symbol, p2: Symbol) = sub2(p2.info) <:< sub1(p1.info) + def cmp(p1: Symbol, p2: Symbol) = ( + methodHigherOrderTypeParamsSubVariance(p2, p1) + && sub2(p2.info) <:< sub1(p1.info) + ) (tparams1 corresponds tparams2)(cmp) && (sub1(res1) <:< sub2(res2)) } diff --git a/test/files/neg/t2066.check b/test/files/neg/t2066.check new file mode 100644 index 0000000000..efade87e26 --- /dev/null +++ b/test/files/neg/t2066.check @@ -0,0 +1,21 @@ +t2066.scala:6: error: overriding method f in trait A1 of type [T[_]]=> Unit; + method f has incompatible type + override def f[T[+_]] = () + ^ +t2066.scala:10: error: overriding method f in trait A1 of type [T[_]]=> Unit; + method f has incompatible type + override def f[T[-_]] = () + ^ +t2066.scala:23: error: overriding method f in trait A2 of type [T[+_]]=> Unit; + method f has incompatible type + override def f[T[-_]] = () + ^ +t2066.scala:45: error: overriding method f in trait A4 of type [T[X[+_]]]=> Unit; + method f has incompatible type + override def f[T[X[_]]] = () + ^ +t2066.scala:53: error: overriding method f in trait A5 of type [T[X[-_]]]=> Unit; + method f has incompatible type + override def f[T[X[_]]] = () + ^ +5 errors found diff --git a/test/files/neg/t2066.scala b/test/files/neg/t2066.scala new file mode 100644 index 0000000000..7f15d39c67 --- /dev/null +++ b/test/files/neg/t2066.scala @@ -0,0 +1,70 @@ +trait A1 { + def f[T[_]] = () +} + +trait B1 extends A1 { + override def f[T[+_]] = () +} + +trait C1 extends A1 { + override def f[T[-_]] = () +} + + +trait A2 { + def f[T[+_]] = () +} + +trait B2 extends A2 { + override def f[T[_]] = () // okay +} + +trait C2 extends A2 { + override def f[T[-_]] = () +} + + +trait A3 { + def f[T[-_]] = () +} + +trait B3 extends A3 { + override def f[T[_]] = () // okay +} + +trait C3 extends A3 { + override def f[T[-_]] = () +} + + +trait A4 { + def f[T[X[+_]]] = () +} + +trait B4 extends A4 { + override def f[T[X[_]]] = () +} + +trait A5 { + def f[T[X[-_]]] = () +} + +trait B5 extends A5 { + override def f[T[X[_]]] = () +} + + + +trait A6 { + def f[T[X[_]]] = () +} + +trait B6 extends A6 { + override def f[T[X[+_]]] = () // okay +} +trait C6 extends A6 { + override def f[T[X[_]]] = () // okay +} +trait D6 extends A6 { + override def f[T[X[-_]]] = () +} diff --git a/test/files/neg/t2066b.check b/test/files/neg/t2066b.check new file mode 100644 index 0000000000..097c44fef3 --- /dev/null +++ b/test/files/neg/t2066b.check @@ -0,0 +1,5 @@ +t2066b.scala:7: error: overriding method f in trait A of type [T[_]](x: T[Int])T[Any]; + method f has incompatible type + def f[T[+_]](x : T[Int]) : T[Any] = x + ^ +one error found diff --git a/test/pending/neg/t2066.scala b/test/files/neg/t2066b.scala index 46177b19f7..46177b19f7 100644 --- a/test/pending/neg/t2066.scala +++ b/test/files/neg/t2066b.scala diff --git a/test/files/pos/t2066.scala b/test/files/pos/t2066.scala new file mode 100644 index 0000000000..30cb99d45c --- /dev/null +++ b/test/files/pos/t2066.scala @@ -0,0 +1,25 @@ +trait A1 { + def f[T[+_]] = () +} + +trait B1 extends A1 { + override def f[T[_]] = () +} + + +trait A2 { + def f[T[-_]] = () +} + +trait B2 extends A2 { + override def f[T[_]] = () +} + + +trait A3 { + def f[T[X[_]]] = () +} + +trait B3 extends A3 { + override def f[T[X[+_]]] = () +} |