Skip to content

Commit 724e0ca

Browse files
committed
break cycle in computeAsSeenFrom when type-checking mutually referencing abstract type members
1 parent 99c19a7 commit 724e0ca

File tree

5 files changed

+153
-14
lines changed

5 files changed

+153
-14
lines changed

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

+28-1
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,34 @@ object Denotations {
10801080

10811081
type AsSeenFromResult = SingleDenotation
10821082

1083-
protected def computeAsSeenFrom(pre: Type)(using Context): SingleDenotation = {
1083+
private var seenFromPre: Type | Null = null
1084+
private var seenFromIntermediateResult: SingleDenotation | Null = null
1085+
1086+
private inline def breakSeenFromCycles(pre: Type)(inline body: SingleDenotation)(using Context) =
1087+
if (seenFromPre eq pre) && symbol.isAbstractType then
1088+
if seenFromIntermediateResult == null then
1089+
seenFromIntermediateResult = newLikeThis(symbol, info, pre, isRefinedMethod)
1090+
seenFromIntermediateResult.nn
1091+
else
1092+
val previousPre = seenFromPre
1093+
val previousIntermediateResult = seenFromIntermediateResult
1094+
1095+
seenFromPre = pre
1096+
seenFromIntermediateResult = null
1097+
1098+
try
1099+
val result = body
1100+
if seenFromIntermediateResult != null then
1101+
seenFromIntermediateResult.nn.myInfo = result.info
1102+
seenFromIntermediateResult.nn
1103+
else
1104+
result
1105+
finally
1106+
seenFromIntermediateResult = previousIntermediateResult
1107+
seenFromPre = previousPre
1108+
end breakSeenFromCycles
1109+
1110+
protected def computeAsSeenFrom(pre: Type)(using Context): SingleDenotation = breakSeenFromCycles(pre) {
10841111
val symbol = this.symbol
10851112
val owner = this match {
10861113
case thisd: SymDenotation => thisd.owner

tests/neg-deep-subtype/i318.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
object i318 {
2+
trait Y {
3+
type A <: { type T >: B }
4+
type B >: { type T >: A }
5+
}
6+
7+
val y: Y = ???
8+
val a: y.A = ???
9+
val b: y.B = a // error: type mismatch
10+
}

tests/neg/i4368.scala

+3-13
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object Test2 {
2323
type A
2424
type B = z.A
2525
}
26-
trait Z extends X with Y // error: cyclic
26+
trait Z extends X with Y { z: W => } // error: cyclic
2727
}
2828

2929
object Test3 {
@@ -41,7 +41,7 @@ object Test3 {
4141
}
4242

4343
object App {
44-
type Z = X with Y
44+
type Z = X & Y
4545
val z: Z = z
4646
val a: z.A = a // error: too deep
4747
}
@@ -155,19 +155,9 @@ object i4369 {
155155
}
156156
object i4370 {
157157
class Foo { type R = A }
158-
type A = List[Foo#R] // error: cyclic
158+
type A = List[Foo#R] // error: type mismatch
159159
}
160160
object i4371 {
161161
class Foo { type A = Boo#B } // error: cyclic
162162
class Boo { type B = Foo#A }
163163
}
164-
object i318 {
165-
trait Y {
166-
type A <: { type T >: B }
167-
type B >: { type T >: A }
168-
}
169-
170-
val y: Y = ???
171-
val a: y.A = ??? // error: too deep
172-
val b: y.B = a // error: too deep
173-
}

tests/neg/i4560.scala

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
object Test1:
2+
trait Test[T]
3+
4+
trait Abstract[T]:
5+
type Foo <: Any { type Tie <: Test[Bar] & Test[o.Nested] }
6+
type Bar <: Any { type Tie <: Test[Foo] }
7+
8+
object o:
9+
type Nested <: Foo { type Tie <: Test[Bar] & Test[Nested] & Test[OtherNested] }
10+
type OtherNested <: Any { type Tie <: Test[Nested] }
11+
12+
trait AbstractIntermediate[T] extends Abstract[T]:
13+
type Bar <: Any { type Tie <: Test[Foo]; type U <: T }
14+
15+
trait ConcreteIntermediate extends AbstractIntermediate[Int]:
16+
type Foo <: Any { type Tie <: Test[Bar] & Test[o.Nested] & Test[o.OtherNested]; type U <: Int }
17+
18+
object concrete extends ConcreteIntermediate:
19+
type SuperBar
20+
type Foo <: Any { type Tie <: Test[Bar] & Test[o.Nested] & Test[o.OtherNested]; type U <: Int }
21+
22+
val a: Foo = ???
23+
val b: a.U = ???
24+
val c: String = b // error: type mismatch
25+
26+
val x: Bar = ???
27+
val y: x.U = ???
28+
val z: String = y // error: type mismatch
29+
30+
31+
object Test2:
32+
class C0: // error: cyclic
33+
type T <: C1#T // error: cyclic
34+
35+
class C1:
36+
type T <: C2#T // error: cyclic // error: cyclic
37+
38+
class C2:
39+
type T <: C3#T // error: cyclic // error: cyclic
40+
41+
class C3: // error: cyclic
42+
type T <: C0#T // error: cyclic // error: cyclic

tests/pos/i4560.scala

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
object Test1:
2+
trait SimpleTrait:
3+
type A <: { type T = B }
4+
type B <: A
5+
6+
trait SimpleSubTrait extends SimpleTrait:
7+
val v: A
8+
9+
10+
object Test2:
11+
trait Trait:
12+
type A <: { type T = B }
13+
type B <: { type S = A }
14+
15+
trait SubTrait extends Trait:
16+
val v: A
17+
18+
class XA:
19+
type T = XB
20+
21+
class XB:
22+
type S = XA
23+
24+
class Foo extends Trait:
25+
type A = XA
26+
type B = XB
27+
28+
29+
object Test3:
30+
trait Test[T]
31+
32+
trait Abstract[T]:
33+
type Foo <: Any { type Tie <: Test[Bar] & Test[o.Nested] }
34+
type Bar <: Any { type Tie <: Test[Foo] }
35+
36+
object o:
37+
type Nested <: Foo { type Tie <: Test[Bar] & Test[Nested] & Test[OtherNested] }
38+
type OtherNested <: Any { type Tie <: Test[Nested] }
39+
40+
trait AbstractIntermediate[T] extends Abstract[T]:
41+
type Bar <: Any { type Tie <: Test[Foo]; type U <: T }
42+
43+
trait ConcreteIntermediate extends AbstractIntermediate[Int]:
44+
type Foo <: Any { type Tie <: Test[Bar] & Test[o.Nested] & Test[o.OtherNested]; type U <: Int }
45+
46+
object concrete extends ConcreteIntermediate:
47+
type SuperFoo
48+
type Foo <: SuperFoo { type Tie <: Test[Bar] & Test[o.Nested] & Test[o.OtherNested]; type U <: Int }
49+
50+
val a: Foo = ???
51+
val b: a.U = ???
52+
val c: Int = b
53+
54+
val x: Bar = ???
55+
val y: x.U = ???
56+
val z: Int = y
57+
58+
59+
object Test4:
60+
class C0:
61+
type T <: { type X <: C1#T }
62+
63+
class C1:
64+
type T <: { type X <: C2#T }
65+
66+
class C2:
67+
type T <: { type X <: C3#T }
68+
69+
class C3:
70+
type T <: { type X <: C0#T }

0 commit comments

Comments
 (0)