From 426b18cc7b40685423cef390465497f652a449c9 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 6 Feb 2019 10:51:34 +0100 Subject: [PATCH 1/2] Fix #5826: specialize union types to avoid constraint cut --- .../tools/dotc/transform/TypeTestsCasts.scala | 24 +++++++++++++------ .../neg-custom-args/isInstanceOf/3324f.scala | 3 ++- .../neg-custom-args/isInstanceOf/i5826.scala | 20 ++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 tests/neg-custom-args/isInstanceOf/i5826.scala diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 3af74f4a7de0..b0bac608048e 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -96,9 +96,9 @@ object TypeTestsCasts { val tvars = constrained(typeLambda, untpd.EmptyTree, alwaysAddTypeVars = true)._2.map(_.tpe) val P1 = tycon.appliedTo(tvars) - debug.println("P : " + P) - debug.println("P1 : " + P1) - debug.println("X : " + X) + debug.println("P : " + P.show) + debug.println("P1 : " + P1.show) + debug.println("X : " + X.show) P1 <:< X // constraint P1 @@ -106,7 +106,7 @@ object TypeTestsCasts { maximizeType(P1, span, fromScala2x = true) val res = P1 <:< P - debug.println("P1 : " + P1) + debug.println("P1 : " + P1.show) debug.println("P1 <:< P = " + res) res @@ -122,9 +122,19 @@ object TypeTestsCasts { case _ => recur(defn.AnyType, tpT) } case tpe: AppliedType => - // first try withou striping type parameters for performance - isClassDetermined(X, tpe)(ctx.fresh.setNewTyperState()) || - isClassDetermined(stripTypeParam(X), tpe)(ctx.fresh.setNewTyperState()) + X.widen match { + case OrType(tp1, tp2) => + // This case is required to retrofit type inference, + // which cut constraints in the following two cases: + // - T1 <:< T2 | T3 + // - T1 & T2 <:< T3 + // See TypeComparer#either + recur(tp1, P) && recur(tp2, P) + case _ => + // first try withou striping type parameters for performance + isClassDetermined(X, tpe)(ctx.fresh.setNewTyperState()) || + isClassDetermined(stripTypeParam(X), tpe)(ctx.fresh.setNewTyperState()) + } case AndType(tp1, tp2) => recur(X, tp1) && recur(X, tp2) case OrType(tp1, tp2) => recur(X, tp1) && recur(X, tp2) case AnnotatedType(t, _) => recur(X, t) diff --git a/tests/neg-custom-args/isInstanceOf/3324f.scala b/tests/neg-custom-args/isInstanceOf/3324f.scala index f1701785bc44..431c2710e47b 100644 --- a/tests/neg-custom-args/isInstanceOf/3324f.scala +++ b/tests/neg-custom-args/isInstanceOf/3324f.scala @@ -3,6 +3,7 @@ class D[T] class Test { def foo[T](x: C[T]) = x match { - case _: D[T] => // error + case _: D[T] => // error + case _: C[Int] => // error } } \ No newline at end of file diff --git a/tests/neg-custom-args/isInstanceOf/i5826.scala b/tests/neg-custom-args/isInstanceOf/i5826.scala new file mode 100644 index 000000000000..bff95e740b4f --- /dev/null +++ b/tests/neg-custom-args/isInstanceOf/i5826.scala @@ -0,0 +1,20 @@ +class Foo { + def test[A]: List[Int] | A => Int = { + case ls: List[Int] => ls.head // error + case _ => 0 + } + + def test2: List[Int] | List[String] => Int = { + case ls: List[Int] => ls.head // error + case _ => 0 + } + + trait A[T] + trait B[T] + + // suppose: class C extends A[Int] with B[String] + def test3[X]: A[X] | B[X] => Int = { + case ls: A[X] => 4 // error + case _ => 0 + } +} From fe21298f1f2c640c93b17cfeea905f592804c463 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 6 Feb 2019 23:58:40 +0100 Subject: [PATCH 2/2] Address review --- tests/neg-custom-args/isInstanceOf/i5826b.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/neg-custom-args/isInstanceOf/i5826b.scala diff --git a/tests/neg-custom-args/isInstanceOf/i5826b.scala b/tests/neg-custom-args/isInstanceOf/i5826b.scala new file mode 100644 index 000000000000..025eb39c4f88 --- /dev/null +++ b/tests/neg-custom-args/isInstanceOf/i5826b.scala @@ -0,0 +1,11 @@ +class Foo { + def test1[A]: List[Int] | A => Int = { + case ls: List[_] => ls.head // error + case _ => 0 + } + + def test2[A]: List[Int] | A => Int = { + case ls: List[_] => ls.size + case _ => 0 + } +}