From bb9ba6b6d198900bb0af0127ac979a13d67520e3 Mon Sep 17 00:00:00 2001 From: Yichen Xu Date: Thu, 8 Jul 2021 15:57:04 +0800 Subject: [PATCH 1/3] Propagate bounds when unifying type parameters --- .../dotty/tools/dotc/core/ConstraintHandling.scala | 1 + .../dotty/tools/dotc/core/OrderingConstraint.scala | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index b429635371ef..7c76c075cb07 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -197,6 +197,7 @@ trait ConstraintHandling { private def unify(p1: TypeParamRef, p2: TypeParamRef)(using Context): Boolean = { constr.println(s"unifying $p1 $p2") assert(constraint.isLess(p1, p2)) + constraint = constraint.addLess(p2, p1) val down = constraint.exclusiveLower(p2, p1) val up = constraint.exclusiveUpper(p1, p2) constraint = constraint.unify(p1, p2) diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index 89bf84d1ed03..c3c7c69f9ee6 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -353,8 +353,15 @@ class OrderingConstraint(private val boundsMap: ParamBounds, else { assert(contains(param1), i"$param1") assert(contains(param2), i"$param2") - val newUpper = param2 :: exclusiveUpper(param2, param1) - val newLower = param1 :: exclusiveLower(param1, param2) + // Is `order` called during parameter unification? + val unifying = isLess(param2, param1) + val newUpper = param2 :: exclusiveUpper(param2, param1).filterNot(_ eq param1) + val newLower = + if unifying then + // Do not add bounds for param1 since it will be unified to param2 soon. + exclusiveLower(param1, param2).filterNot(_ eq param2) + else + param1 :: exclusiveLower(param1, param2).filterNot(_ eq param2) val current1 = newLower.foldLeft(current)(upperLens.map(this, _, _, newUpper ::: _)) val current2 = newUpper.foldLeft(current1)(lowerLens.map(this, _, _, newLower ::: _)) current2 From 4fde6184e8f7960e2e2430f0bc9870f7b60f5c19 Mon Sep 17 00:00:00 2001 From: Yichen Xu Date: Thu, 8 Jul 2021 16:13:51 +0800 Subject: [PATCH 2/3] Refactor special handling for unification in `order` --- .../tools/dotc/core/OrderingConstraint.scala | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index c3c7c69f9ee6..450301188474 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -355,13 +355,25 @@ class OrderingConstraint(private val boundsMap: ParamBounds, assert(contains(param2), i"$param2") // Is `order` called during parameter unification? val unifying = isLess(param2, param1) - val newUpper = param2 :: exclusiveUpper(param2, param1).filterNot(_ eq param1) - val newLower = + val newUpper = { + val up = exclusiveUpper(param2, param1) + if unifying then + // Since param2 <:< param1 already holds now, filter out param1 to avoid adding + // duplicated orderings. + param2 :: up.filterNot(_ eq param1) + else + param2 :: up + } + val newLower = { + val lower = exclusiveLower(param1, param2) if unifying then // Do not add bounds for param1 since it will be unified to param2 soon. - exclusiveLower(param1, param2).filterNot(_ eq param2) + // And, similarly filter out param2 from lowerly-ordered parameters + // to avoid duplicated orderings. + lower.filterNot(_ eq param2) else - param1 :: exclusiveLower(param1, param2).filterNot(_ eq param2) + param1 :: lower + } val current1 = newLower.foldLeft(current)(upperLens.map(this, _, _, newUpper ::: _)) val current2 = newUpper.foldLeft(current1)(lowerLens.map(this, _, _, newLower ::: _)) current2 From d1fca8a7e9af6f7d53f9e1b0673b3377e09b41ad Mon Sep 17 00:00:00 2001 From: Yichen Xu Date: Thu, 8 Jul 2021 17:33:37 +0800 Subject: [PATCH 3/3] Add pos test --- tests/pos/gadt-param-unification.scala | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/pos/gadt-param-unification.scala diff --git a/tests/pos/gadt-param-unification.scala b/tests/pos/gadt-param-unification.scala new file mode 100644 index 000000000000..39c944469d74 --- /dev/null +++ b/tests/pos/gadt-param-unification.scala @@ -0,0 +1,6 @@ +trait Expr[T] +final class Lit[T] extends Expr[T] + +def foo[X, T1 >: X, T2](m: Expr[T2]): T2 = m match { + case _: Lit[T1] => ??? : X +}