summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2014-01-13 10:45:38 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2014-01-13 10:45:38 -0800
commit34c8a00da7a14803a7f38927ba11926561b2a188 (patch)
treedb89325af094b4bdd9df7f6e0f57df898711dded
parent0a43c263568760ad291cbc76a98e1eb2de9292a7 (diff)
parent28d3390e07715b0dcb5ce2f68d72d5a44e6ca74d (diff)
downloadscala-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.scala16
-rw-r--r--test/files/neg/t2066.check21
-rw-r--r--test/files/neg/t2066.scala70
-rw-r--r--test/files/neg/t2066b.check5
-rw-r--r--test/files/neg/t2066b.scala (renamed from test/pending/neg/t2066.scala)0
-rw-r--r--test/files/pos/t2066.scala25
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[+_]]] = ()
+}