aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-01-10 18:50:48 +0700
committerMartin Odersky <odersky@gmail.com>2017-01-10 18:50:48 +0700
commit2144462b39a6d92d7c3653e9bb242d116a60caba (patch)
treebd196752348fbab68892644af3f3bdb3fd0e97b3
parentbe6464366fdbccc12623970445d8d5e8deff3f3f (diff)
downloaddotty-2144462b39a6d92d7c3653e9bb242d116a60caba.tar.gz
dotty-2144462b39a6d92d7c3653e9bb242d116a60caba.tar.bz2
dotty-2144462b39a6d92d7c3653e9bb242d116a60caba.zip
Fix #1891: Don't add redundant constraint
Before adding a constraint, make sure there is no way the two types are already in a subtype relation. Adding redundant constraints is problematic because we might introduce cycles. See i1891.scala for a test.
-rw-r--r--compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala12
-rw-r--r--tests/pos/i1891.scala11
3 files changed, 22 insertions, 2 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 0e155b9e1..42df53fed 100644
--- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -57,6 +57,7 @@ trait ConstraintHandling {
b match {
case b: AndOrType => occursIn(b.tp1) || occursIn(b.tp2)
case b: TypeVar => occursIn(b.origin)
+ case b: TermRef => occursIn(b.underlying)
case _ => false
}
}
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index 8930983f3..baebd4214 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -375,11 +375,19 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
thirdTryNamed(tp1, tp2)
case tp2: PolyParam =>
def comparePolyParam =
- (ctx.mode is Mode.TypevarsMissContext) ||
- isSubTypeWhenFrozen(tp1, bounds(tp2).lo) || {
+ (ctx.mode is Mode.TypevarsMissContext) || {
+ val alwaysTrue =
+ // The following condition is carefully formulated to catch all cases
+ // where the subtype relation is true without needing to add a constraint
+ // It's tricky because we might need to either appriximate tp2 by its
+ // lower bound or else widen tp1 and check that the result is a subtype of tp2.
+ if (frozenConstraint || alwaysFluid) isSubType(tp1, bounds(tp2).lo)
+ else isSubTypeWhenFrozen(tp1, tp2)
+ alwaysTrue || {
if (canConstrain(tp2)) addConstraint(tp2, tp1.widenExpr, fromBelow = true)
else fourthTry(tp1, tp2)
}
+ }
comparePolyParam
case tp2: RefinedType =>
def compareRefinedSlow: Boolean = {
diff --git a/tests/pos/i1891.scala b/tests/pos/i1891.scala
new file mode 100644
index 000000000..b178c256b
--- /dev/null
+++ b/tests/pos/i1891.scala
@@ -0,0 +1,11 @@
+object Test {
+ class CC2[A, B](a: A, b: B)
+
+ type T2[A, B] = CC2[A, B]
+
+ class ArrowAssoc[A](val self: A) {
+ @inline def f[B](y: B): CC2[A, B] = new CC2(self, y)
+ }
+
+ def foo = (new ArrowAssoc(1)).f(2)
+}