Skip to content

Commit 951a726

Browse files
authored
Merge pull request #11237 from dotty-staging/fix-11234
Fix #11234: Avoid cycles in unifying F-bounded type parameters
2 parents bd9926d + e0b861c commit 951a726

File tree

4 files changed

+29
-8
lines changed

4 files changed

+29
-8
lines changed

compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,9 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
393393
order(this, param1, param2).checkNonCyclic()
394394

395395
def unify(p1: TypeParamRef, p2: TypeParamRef)(using Context): This =
396-
val p1Bounds = (nonParamBounds(p1) & nonParamBounds(p2)).substParam(p2, p1)
396+
val bound1 = nonParamBounds(p1).substParam(p2, p1)
397+
val bound2 = nonParamBounds(p2).substParam(p2, p1)
398+
val p1Bounds = bound1 & bound2
397399
updateEntry(p1, p1Bounds).replace(p2, p1)
398400

399401
// ---------- Replacements and Removals -------------------------------------

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
390390
}
391391
def compareTypeParamRef =
392392
assumedTrue(tp1) ||
393+
tp2.match {
394+
case tp2: TypeParamRef => constraint.isLess(tp1, tp2)
395+
case _ => false
396+
} ||
393397
isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
394398
if (canConstrain(tp1) && !approx.high)
395399
addConstraint(tp1, tp2, fromBelow = false) && flagNothingBound
@@ -540,11 +544,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
540544
// widening in `fourthTry` before adding to the constraint.
541545
if (frozenConstraint) recur(tp1, bounds(tp2).lo)
542546
else isSubTypeWhenFrozen(tp1, tp2)
543-
alwaysTrue ||
544-
frozenConstraint && (tp1 match {
545-
case tp1: TypeParamRef => constraint.isLess(tp1, tp2)
546-
case _ => false
547-
}) || {
547+
alwaysTrue || {
548548
if (canConstrain(tp2) && !approx.low)
549549
addConstraint(tp2, tp1.widenExpr, fromBelow = true)
550550
else fourthTry
@@ -2122,7 +2122,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
21222122
}
21232123

21242124
private def andTypeGen(tp1: Type, tp2: Type, op: (Type, Type) => Type,
2125-
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
2125+
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"andTypeGen(${tp1.show}, ${tp2.show})", subtyping, show = true) {
21262126
val t1 = distributeAnd(tp1, tp2)
21272127
if (t1.exists) t1
21282128
else {

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotc
33
package core
44

55
import Contexts._, Types._, Symbols._, Names._, Flags._
6-
import Denotations._, SymDenotations._
6+
import SymDenotations._
77
import util.Spans._
88
import util.Stats
99
import NameKinds.DepParamName

tests/pos/i11234.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
trait Foo[A <: Foo[A]]
2+
trait FooCreator[A <: Foo[A]] {
3+
def createFoo(): A
4+
}
5+
6+
trait FooWrapper {
7+
type A <: Foo[A]
8+
def foo: A
9+
}
10+
11+
object FooWrapper {
12+
def apply[A0 <: Foo[A0]](toWrap: A0): FooWrapper { type A = A0 } = new FooWrapper {
13+
type A = A0
14+
def foo: A0 = toWrap
15+
}
16+
}
17+
18+
def error(fooWrapper: FooWrapper, processor: [A <: Foo[A]] => A => A): FooWrapper =
19+
FooWrapper(processor(fooWrapper.foo))

0 commit comments

Comments
 (0)