From 49fc0047b82b860bd2f5b72195a6d7727f4f2d85 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 21 May 2020 14:06:39 +0200 Subject: [PATCH 1/3] Fix #9016: Fix stackoverflows in provablyDisjoint --- .../src/dotty/tools/dotc/core/TypeComparer.scala | 6 ++++-- tests/run/enum-Tree.scala | 15 ++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 61cca387473c..abbdb1791ec4 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2417,9 +2417,11 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w (provablyDisjoint(tp1.tp1, tp2.tp1) || provablyDisjoint(tp1.tp2, tp2.tp2)) && (provablyDisjoint(tp1.tp1, tp2.tp2) || provablyDisjoint(tp1.tp2, tp2.tp1)) case (tp1: AndType, _) => - provablyDisjoint(tp1.tp2, tp2) || provablyDisjoint(tp1.tp1, tp2) + !(tp1 <:< tp2) + && (provablyDisjoint(tp1.tp2, tp2) || provablyDisjoint(tp1.tp1, tp2)) case (_, tp2: AndType) => - provablyDisjoint(tp1, tp2.tp2) || provablyDisjoint(tp1, tp2.tp1) + !(tp2 <:< tp1) + && (provablyDisjoint(tp1, tp2.tp2) || provablyDisjoint(tp1, tp2.tp1)) case (tp1: TypeProxy, tp2: TypeProxy) => provablyDisjoint(tp1.underlying, tp2) || provablyDisjoint(tp1, tp2.underlying) case (tp1: TypeProxy, _) => diff --git a/tests/run/enum-Tree.scala b/tests/run/enum-Tree.scala index e0c7a8ebc302..77f08c997bad 100644 --- a/tests/run/enum-Tree.scala +++ b/tests/run/enum-Tree.scala @@ -1,12 +1,13 @@ +trait P enum Tree[T] { - case True extends Tree[Boolean] - case False extends Tree[Boolean] - case Zero extends Tree[Int] - case Succ(n: Tree[Int]) extends Tree[Int] - case Pred(n: Tree[Int]) extends Tree[Int] - case IsZero(n: Tree[Int]) extends Tree[Boolean] + case True extends Tree[Boolean], P + case False extends Tree[Boolean], P + case Zero extends Tree[Int], P + case Succ(n: Tree[Int]) extends Tree[Int], P + case Pred(n: Tree[Int]) extends Tree[Int], P + case IsZero(n: Tree[Int]) extends Tree[Boolean], P case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T]) - extends Tree[T] + extends Tree[T], P } object Test { From 6ea1a7b0fea380c1c43af143b178962d6800429e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 21 May 2020 14:19:24 +0200 Subject: [PATCH 2/3] Drop non-sensical case in provablyDisjoint Surely, two intersection types A1 & A2 and B1 & B2 are provable disjoint if any pair of A_i and B_j is provably disjoint? This is already handled by the single-side cases for AndTypes. The dropped case imposed a stronger condition. --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index abbdb1791ec4..7ae72bf4317f 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2413,9 +2413,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w provablyDisjoint(tp1.tp1, tp2) && provablyDisjoint(tp1.tp2, tp2) case (_, tp2: OrType) => provablyDisjoint(tp1, tp2.tp1) && provablyDisjoint(tp1, tp2.tp2) - case (tp1: AndType, tp2: AndType) => - (provablyDisjoint(tp1.tp1, tp2.tp1) || provablyDisjoint(tp1.tp2, tp2.tp2)) && - (provablyDisjoint(tp1.tp1, tp2.tp2) || provablyDisjoint(tp1.tp2, tp2.tp1)) case (tp1: AndType, _) => !(tp1 <:< tp2) && (provablyDisjoint(tp1.tp2, tp2) || provablyDisjoint(tp1.tp1, tp2)) From 157ad2599e241db2311a1e30cdd7152e22fb43fd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 21 May 2020 15:13:36 +0200 Subject: [PATCH 3/3] Fix exhaustivity test --- tests/patmat/andtype-opentype-interaction.check | 1 - tests/patmat/andtype-opentype-interaction.scala | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/patmat/andtype-opentype-interaction.check b/tests/patmat/andtype-opentype-interaction.check index d42d03bb240c..a9d8618adad0 100644 --- a/tests/patmat/andtype-opentype-interaction.check +++ b/tests/patmat/andtype-opentype-interaction.check @@ -2,6 +2,5 @@ 27: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenTrait2, _: Clazz & OpenTrait & OpenTrait2, _: AbstractClass & OpenTrait & OpenTrait2, _: SealedClass & OpenTrait & OpenTrait2 31: Pattern Match Exhaustivity: _: Trait & OpenClass 35: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenClass -39: Pattern Match Exhaustivity: _: Trait & OpenClass & (OpenTrait & OpenClass2) 43: Pattern Match Exhaustivity: _: Trait & OpenAbstractClass 47: Pattern Match Exhaustivity: _: Trait & OpenClass & (OpenTrait & OpenClassSubclass) diff --git a/tests/patmat/andtype-opentype-interaction.scala b/tests/patmat/andtype-opentype-interaction.scala index 942fd9814599..788e1346f891 100644 --- a/tests/patmat/andtype-opentype-interaction.scala +++ b/tests/patmat/andtype-opentype-interaction.scala @@ -37,7 +37,7 @@ object Test { } def m2c(s: (T & OpenClass) & (OpenTrait & OpenClass2)) = s match { - case _: Unrelated => ; + case _: Unrelated => ; // OK since scrutinee is the empty type } def m3(s: T & OpenAbstractClass) = s match {