diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index e8e7b534dc3e..27ca38d807d4 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -109,7 +109,24 @@ trait ConstraintHandling[AbstractContext] { (c1 eq constraint) || { constraint = c1 val TypeBounds(lo, hi) = constraint.entry(param) - isSubType(lo, hi) + hi match { + case AppliedType(tr: TypeRef, targs) => + val recursiveBound: Boolean = + targs.exists { + case lr: LazyRef => lr.ref == param + case _ => false + } + if(!recursiveBound) isSubType(lo, hi) + else + tr.underlying match { + case TypeBounds(trlo, trhi) if trlo.isMatch || trhi.isMatch => + true + case _ => + isSubType(lo, hi) + } + case _ => + isSubType(lo, hi) + } } } } diff --git a/compiler/test/dotc/pos-from-tasty.blacklist b/compiler/test/dotc/pos-from-tasty.blacklist index 64aff439e0f8..5c2ebebe29c1 100644 --- a/compiler/test/dotc/pos-from-tasty.blacklist +++ b/compiler/test/dotc/pos-from-tasty.blacklist @@ -20,3 +20,5 @@ default-super.scala i3050.scala i4006b.scala i4006c.scala + +i5535.scala diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist index 90cd8dbf757e..21ac05fbc606 100644 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ b/compiler/test/dotc/pos-test-pickling.blacklist @@ -10,3 +10,4 @@ t3249 t3486 t3612.scala typelevel0.scala +i5535.scala diff --git a/tests/neg/i5535.scala b/tests/neg/i5535.scala new file mode 100644 index 000000000000..4801799c2365 --- /dev/null +++ b/tests/neg/i5535.scala @@ -0,0 +1,15 @@ +object Test2 { + // The identity on types of the form N | P[a, P[b, ... P[z, N]]] + type Nested[X, P[_, _], N] = X match { + case N => N + case P[a, b] => P[a, Nested[b, P, N]] + } + + // Type bound: + // Recursion limit exceeded. + // Maybe there is an illegal cyclic reference? + def p1[T <: Nested[T, Tuple2, Unit]](t: T): T = t + //p1(()) + p1((23, 24)) // error + p1(("foo", (23, 24))) // error +} diff --git a/tests/pos/i5535.scala b/tests/pos/i5535.scala new file mode 100644 index 000000000000..3bc72d452776 --- /dev/null +++ b/tests/pos/i5535.scala @@ -0,0 +1,38 @@ +object Test1 { + // The identity on Unit + type IdUnit[X] = X match { + case Unit => Unit + } + + // Type bound: + // Recursion limit exceeded. + // Maybe there is an illegal cyclic reference? + def p1[T <: IdUnit[T]](t: T): T = t + p1(()) + + // Type constraint: OK + def p2[T](t: T)(implicit ev: T <:< IdUnit[T]): T = t + p2(()) +} + +object Test2 { + // The identity on types of the form N | P[a, P[b, ... P[z, N]]] + type Nested[X, P[_, _], N] = X match { + case N => N + case P[a, b] => P[a, Nested[b, P, N]] + } + + // Type bound: + // Recursion limit exceeded. + // Maybe there is an illegal cyclic reference? + def p1[T <: Nested[T, Tuple2, Unit]](t: T): T = t + p1(()) + p1((23, ())) + p1(("foo", (23, ()))) + + // Type constraint: OK + def p2[T](t: T)(erased implicit ev: T <:< Nested[T, Tuple2, Unit]): T = t + p2(()) + p2((23, ())) + p2(("foo", (23, ()))) +}