Skip to content

Commit 958acc6

Browse files
Backport "Fix problems with cycle checks" to LTS (#20833)
Backports #19453 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents c0b8c17 + 679fd17 commit 958acc6

File tree

8 files changed

+180
-81
lines changed

8 files changed

+180
-81
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ object Symbols extends SymUtils {
129129
final def lastKnownDenotation: SymDenotation =
130130
lastDenot
131131

132-
private[core] def defRunId: RunId =
132+
private[dotc] def defRunId: RunId =
133133
lastDenot.validFor.runId
134134

135135
private inline def associatedFileMatches(inline filter: AbstractFile => Boolean)(using Context): Boolean =

compiler/src/dotty/tools/dotc/reporting/messages.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -2546,12 +2546,11 @@ class UnknownNamedEnclosingClassOrObject(name: TypeName)(using Context)
25462546

25472547
class IllegalCyclicTypeReference(val ex: CyclicReference, sym: Symbol, where: String, lastChecked: Type)(using Context)
25482548
extends CyclicMsg(IllegalCyclicTypeReferenceID) {
2549-
override def context = ""
25502549
def msg(using Context) =
25512550
val lastCheckedStr =
25522551
try lastChecked.show
25532552
catch case ex: CyclicReference => "..."
2554-
i"illegal cyclic type reference: ${where} ${hl(lastCheckedStr)} of $sym refers back to the type itself"
2553+
i"illegal cyclic type reference: ${where} ${hl(lastCheckedStr)} of $sym refers back to the type itself$context"
25552554
def explain(using Context) = ""
25562555
}
25572556

compiler/src/dotty/tools/dotc/typer/Checking.scala

+34-12
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,14 @@ object Checking {
319319
|| sym.owner.isContainedIn(prefix.cls) // sym reachable through member references
320320
)
321321
case prefix: NamedType =>
322-
(!sym.is(Private) && prefix.derivesFrom(sym.owner)) ||
323-
(!prefix.symbol.moduleClass.isStaticOwner && isInteresting(prefix.prefix))
322+
!sym.is(Private) && prefix.derivesFrom(sym.owner)
323+
|| {
324+
val pcls = prefix.symbol.moduleClass
325+
if pcls.isStaticOwner then
326+
pcls.span.exists && pcls.defRunId == ctx.runId // cheaper approximation to isDefinedInCurrentRun
327+
else
328+
isInteresting(prefix.prefix)
329+
}
324330
case SuperType(thistp, _) => isInteresting(thistp)
325331
case AndType(tp1, tp2) => isInteresting(tp1) || isInteresting(tp2)
326332
case OrType(tp1, tp2) => isInteresting(tp1) && isInteresting(tp2)
@@ -329,15 +335,27 @@ object Checking {
329335
case _ => false
330336
}
331337

332-
if (isInteresting(pre)) {
333-
val pre1 = this(pre, false, false)
334-
if (locked.contains(tp) || tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter])
335-
throw CyclicReference(tp.symbol)
336-
locked += tp
337-
try if (!tp.symbol.isClass) checkInfo(tp.info)
338-
finally locked -= tp
339-
tp.withPrefix(pre1)
340-
}
338+
if isInteresting(pre) then
339+
val traceCycles = CyclicReference.isTraced
340+
try
341+
if traceCycles then
342+
CyclicReference.pushTrace("explore ", tp.symbol, " for cyclic references")
343+
val pre1 = this(pre, false, false)
344+
if locked.contains(tp)
345+
|| tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter]
346+
then
347+
throw CyclicReference(tp.symbol)
348+
locked += tp
349+
try
350+
if tp.symbol.isOpaqueAlias then
351+
checkInfo(TypeAlias(tp.translucentSuperType))
352+
else if !tp.symbol.isClass then
353+
checkInfo(tp.info)
354+
finally
355+
locked -= tp
356+
tp.withPrefix(pre1)
357+
finally
358+
if traceCycles then CyclicReference.popTrace()
341359
else tp
342360
}
343361
catch {
@@ -374,7 +392,11 @@ object Checking {
374392
*/
375393
def checkNonCyclic(sym: Symbol, info: Type, reportErrors: Boolean)(using Context): Type = {
376394
val checker = withMode(Mode.CheckCyclic)(new CheckNonCyclicMap(sym, reportErrors))
377-
try checker.checkInfo(info)
395+
try
396+
val toCheck = info match
397+
case info: RealTypeBounds if sym.isOpaqueAlias => TypeAlias(sym.opaqueAlias)
398+
case _ => info
399+
checker.checkInfo(toCheck)
378400
catch {
379401
case ex: CyclicReference =>
380402
if (reportErrors)

tests/neg/i15507.check

+52-22
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,70 @@
1-
-- Error: tests/neg/i15507.scala:2:40 ----------------------------------------------------------------------------------
2-
2 | type _NestedSet1[X] = Set[_NestedSet1[?]] // error
1+
-- Error: tests/neg/i15507.scala:3:40 ----------------------------------------------------------------------------------
2+
3 | type _NestedSet1[X] = Set[_NestedSet1[?]] // error
33
| ^
44
| no wildcard type allowed here
5-
-- Error: tests/neg/i15507.scala:3:41 ----------------------------------------------------------------------------------
6-
3 | type _NestedSet2[X] <: Set[_NestedSet2[?]] // error
5+
-- Error: tests/neg/i15507.scala:4:41 ----------------------------------------------------------------------------------
6+
4 | type _NestedSet2[X] <: Set[_NestedSet2[?]] // error
77
| ^
88
| no wildcard type allowed here
9-
-- [E140] Cyclic Error: tests/neg/i15507.scala:5:7 ---------------------------------------------------------------------
10-
5 | type _NestedSet4[X] >: Set[_NestedSet4[X]] // error
9+
-- [E140] Cyclic Error: tests/neg/i15507.scala:6:7 ---------------------------------------------------------------------
10+
6 | type _NestedSet4[X] >: Set[_NestedSet4[X]] // error
1111
| ^
1212
| illegal cyclic type reference: lower bound ... of type _NestedSet4 refers back to the type itself
13-
-- [E140] Cyclic Error: tests/neg/i15507.scala:6:7 ---------------------------------------------------------------------
14-
6 | type _NestedSet5[X] = Set[_NestedSet5[X]] // error
13+
|
14+
| The error occurred while trying to compute the signature of type _NestedSet4
15+
| which required to explore type _NestedSet4 for cyclic references
16+
|
17+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
18+
-- [E140] Cyclic Error: tests/neg/i15507.scala:7:7 ---------------------------------------------------------------------
19+
7 | type _NestedSet5[X] = Set[_NestedSet5[X]] // error
1520
| ^
1621
| illegal cyclic type reference: alias ... of type _NestedSet5 refers back to the type itself
17-
-- [E140] Cyclic Error: tests/neg/i15507.scala:7:7 ---------------------------------------------------------------------
18-
7 | type _NestedSet6[X] = Set[_NestedSet6[Int]] // error
22+
|
23+
| The error occurred while trying to compute the signature of type _NestedSet5
24+
| which required to explore type _NestedSet5 for cyclic references
25+
|
26+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
27+
-- [E140] Cyclic Error: tests/neg/i15507.scala:8:7 ---------------------------------------------------------------------
28+
8 | type _NestedSet6[X] = Set[_NestedSet6[Int]] // error
1929
| ^
2030
| illegal cyclic type reference: alias ... of type _NestedSet6 refers back to the type itself
21-
-- Error: tests/neg/i15507.scala:9:43 ----------------------------------------------------------------------------------
22-
9 | type _NestedList1[X] = List[_NestedList1[?]] // error
23-
| ^
24-
| no wildcard type allowed here
25-
-- Error: tests/neg/i15507.scala:10:44 ---------------------------------------------------------------------------------
26-
10 | type _NestedList2[X] <: List[_NestedList2[?]] // error
31+
|
32+
| The error occurred while trying to compute the signature of type _NestedSet6
33+
| which required to explore type _NestedSet6 for cyclic references
34+
|
35+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
36+
-- Error: tests/neg/i15507.scala:10:43 ---------------------------------------------------------------------------------
37+
10 | type _NestedList1[X] = List[_NestedList1[?]] // error
38+
| ^
39+
| no wildcard type allowed here
40+
-- Error: tests/neg/i15507.scala:11:44 ---------------------------------------------------------------------------------
41+
11 | type _NestedList2[X] <: List[_NestedList2[?]] // error
2742
| ^
2843
| no wildcard type allowed here
29-
-- [E140] Cyclic Error: tests/neg/i15507.scala:12:7 --------------------------------------------------------------------
30-
12 | type _NestedList4[X] >: List[_NestedList4[X]] // error
44+
-- [E140] Cyclic Error: tests/neg/i15507.scala:13:7 --------------------------------------------------------------------
45+
13 | type _NestedList4[X] >: List[_NestedList4[X]] // error
3146
| ^
3247
| illegal cyclic type reference: lower bound ... of type _NestedList4 refers back to the type itself
33-
-- [E140] Cyclic Error: tests/neg/i15507.scala:13:7 --------------------------------------------------------------------
34-
13 | type _NestedList5[X] = List[_NestedList5[X]] // error
48+
|
49+
| The error occurred while trying to compute the signature of type _NestedList4
50+
| which required to explore type _NestedList4 for cyclic references
51+
|
52+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
53+
-- [E140] Cyclic Error: tests/neg/i15507.scala:14:7 --------------------------------------------------------------------
54+
14 | type _NestedList5[X] = List[_NestedList5[X]] // error
3555
| ^
3656
| illegal cyclic type reference: alias ... of type _NestedList5 refers back to the type itself
37-
-- [E140] Cyclic Error: tests/neg/i15507.scala:14:7 --------------------------------------------------------------------
38-
14 | type _NestedList6[X] = List[_NestedList6[Int]] // error
57+
|
58+
| The error occurred while trying to compute the signature of type _NestedList5
59+
| which required to explore type _NestedList5 for cyclic references
60+
|
61+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
62+
-- [E140] Cyclic Error: tests/neg/i15507.scala:15:7 --------------------------------------------------------------------
63+
15 | type _NestedList6[X] = List[_NestedList6[Int]] // error
3964
| ^
4065
| illegal cyclic type reference: alias ... of type _NestedList6 refers back to the type itself
66+
|
67+
| The error occurred while trying to compute the signature of type _NestedList6
68+
| which required to explore type _NestedList6 for cyclic references
69+
|
70+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.

tests/neg/i15507.scala

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//> using options -explain-cyclic
12
object TestNested:
23
type _NestedSet1[X] = Set[_NestedSet1[?]] // error
34
type _NestedSet2[X] <: Set[_NestedSet2[?]] // error

tests/neg/i19372.check

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
-- [E140] Cyclic Error: tests/neg/i19372.scala:3:7 ---------------------------------------------------------------------
2+
3 | type AAA = List[bar.BBB] // error: cyclic
3+
| ^
4+
| illegal cyclic type reference: alias List[Test1.bar.BBB] of type AAA refers back to the type itself
5+
|
6+
| The error occurred while trying to compute the signature of type AAA
7+
| which required to explore type BBB for cyclic references
8+
| which required to explore type AAA for cyclic references
9+
|
10+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
11+
-- [E140] Cyclic Error: tests/neg/i19372.scala:9:7 ---------------------------------------------------------------------
12+
9 | type A = bar.B // error: cyclic
13+
| ^
14+
| illegal cyclic type reference: alias Test2.bar.B of type A refers back to the type itself
15+
|
16+
| The error occurred while trying to compute the signature of type A
17+
| which required to explore type B for cyclic references
18+
| which required to explore type A for cyclic references
19+
|
20+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
21+
-- [E140] Cyclic Error: tests/neg/i19372.scala:15:7 --------------------------------------------------------------------
22+
15 | type AAA = List[bar.BBB] // error: cyclic
23+
| ^
24+
| illegal cyclic type reference: alias List[Test3.bar.BBB] of type AAA refers back to the type itself
25+
|
26+
| The error occurred while trying to compute the signature of type AAA
27+
| which required to explore type BBB for cyclic references
28+
| which required to explore type AAA for cyclic references
29+
|
30+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
31+
-- [E140] Cyclic Error: tests/neg/i19372.scala:21:7 --------------------------------------------------------------------
32+
21 | type A = bar.B // error: cyclic
33+
| ^
34+
| illegal cyclic type reference: alias Test4.bar.B of type A refers back to the type itself
35+
|
36+
| The error occurred while trying to compute the signature of type A
37+
| which required to explore type B for cyclic references
38+
| which required to explore type A for cyclic references
39+
|
40+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
41+
-- [E140] Cyclic Error: tests/neg/i19372.scala:30:7 --------------------------------------------------------------------
42+
30 | type UCharIteratorReserved = Ptr[UCharIterator] // error: cyclic
43+
| ^
44+
|illegal cyclic type reference: alias Ptr[structs.UCharIterator] of type UCharIteratorReserved refers back to the type itself
45+
|
46+
|The error occurred while trying to compute the signature of type UCharIteratorReserved
47+
| which required to explore type UCharIterator for cyclic references
48+
| which required to explore type UCharIteratorReserved for cyclic references
49+
|
50+
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.

tests/neg/i19372.scala

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//> using options -explain-cyclic
2+
object Test1:
3+
type AAA = List[bar.BBB] // error: cyclic
4+
def foo: AAA = ???
5+
object bar:
6+
opaque type BBB = AAA
7+
8+
object Test2:
9+
type A = bar.B // error: cyclic
10+
def foo: A = ???
11+
object bar:
12+
opaque type B = A
13+
14+
object Test3:
15+
type AAA = List[bar.BBB] // error: cyclic
16+
def foo: AAA = ???
17+
object bar:
18+
type BBB = AAA
19+
20+
object Test4:
21+
type A = bar.B // error: cyclic
22+
def foo: A = ???
23+
object bar:
24+
type B = A
25+
26+
trait Ptr[T]
27+
28+
object aliases:
29+
import structs.*
30+
type UCharIteratorReserved = Ptr[UCharIterator] // error: cyclic
31+
object UCharIteratorReserved:
32+
def iterator: UCharIterator = ???
33+
34+
object structs:
35+
import aliases.{*, given}
36+
opaque type UCharIterator = Ptr[UCharIteratorReserved]
37+
object UCharIterator:
38+
def reservedFn: UCharIteratorReserved = ???

tests/neg/i8984.scala

+3-44
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import scala.annotation.tailrec
22
type |@[F[+_], G[+_]] = [a] =>> F[a] | G[a]
33

4-
object Fix:
4+
object Fix: // error
55
opaque type T[+F[+_]] = ApplyFix.T[F]
66

7-
def apply[F[+_]](f: F[Fix[F]]): T[F] = ApplyFix(f)
7+
def apply[F[+_]](f: F[Fix[F]]): T[F] = ApplyFix(f) // error // error
88

9-
extension [F[+_]](fix: T[F])
9+
extension [F[+_]](fix: T[F]) // error
1010
def value: F[Fix[F]] = ApplyFix.unwrap(fix)
1111

1212
object ApplyFix:
@@ -18,44 +18,3 @@ object Fix:
1818

1919
type Fix[+F[+_]] = Fix.T[F]
2020

21-
final case class Cat[+R](name: String, fur: String, rest: R)
22-
object Cat:
23-
def of[R, F[+_]](name: String, fur: String, rest: Fix[F]): Fix[F |@ Cat] = Fix(new Cat(name, fur, rest))
24-
25-
final case class Dog[+R](name: String, size: Long, rest: R)
26-
object Dog:
27-
def of[R, F[+_]](name: String, size: Long, rest: Fix[F]): Fix[F |@ Dog] = Fix(new Dog(name, size, rest))
28-
29-
case object End:
30-
type f[+a] = End.type
31-
def apply() = Fix[f](End)
32-
33-
object DropRed:
34-
@tailrec def dropRedCats[F[+a] >: Cat[a]](cats: Fix[F]): Fix[F] =
35-
cats.value match
36-
case Cat(_, "red", rest) => dropRedCats(rest) // error
37-
case _ => cats
38-
39-
type CatDogVector = Vector[Either[Cat[Unit], Dog[Unit]]]
40-
type CatOrDogs[+a] = Cat[a] | Dog[a] | End.type
41-
42-
extension (catDogs: Fix[CatOrDogs]) def toVector : CatDogVector =
43-
@tailrec def go(acc: CatDogVector, catDogs: Fix[CatOrDogs]) : CatDogVector = catDogs.value match
44-
case Cat(name, fur, rest) => go(acc :+ Left(Cat(name, fur, ())), rest)
45-
case Dog(name, size, rest) => go(acc :+ Right(Dog(name, size, ())), rest)
46-
case End => acc
47-
48-
go(Vector(), catDogs)
49-
50-
val x =
51-
Cat.of("lilly" , "red" ,
52-
Cat.of("anya" , "red" ,
53-
Cat.of("boris" , "black",
54-
Dog.of("mashka", 3 ,
55-
Cat.of("manya" , "red" ,
56-
End())))))
57-
58-
59-
def main(args: Array[String]) =
60-
println(x.toVector)
61-
println(dropRedCats(x).toVector)

0 commit comments

Comments
 (0)