Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport "Fix problems with cycle checks" to LTS #20833

Merged
merged 2 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ object Symbols extends SymUtils {
final def lastKnownDenotation: SymDenotation =
lastDenot

private[core] def defRunId: RunId =
private[dotc] def defRunId: RunId =
lastDenot.validFor.runId

private inline def associatedFileMatches(inline filter: AbstractFile => Boolean)(using Context): Boolean =
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2546,12 +2546,11 @@ class UnknownNamedEnclosingClassOrObject(name: TypeName)(using Context)

class IllegalCyclicTypeReference(val ex: CyclicReference, sym: Symbol, where: String, lastChecked: Type)(using Context)
extends CyclicMsg(IllegalCyclicTypeReferenceID) {
override def context = ""
def msg(using Context) =
val lastCheckedStr =
try lastChecked.show
catch case ex: CyclicReference => "..."
i"illegal cyclic type reference: ${where} ${hl(lastCheckedStr)} of $sym refers back to the type itself"
i"illegal cyclic type reference: ${where} ${hl(lastCheckedStr)} of $sym refers back to the type itself$context"
def explain(using Context) = ""
}

Expand Down
46 changes: 34 additions & 12 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,14 @@ object Checking {
|| sym.owner.isContainedIn(prefix.cls) // sym reachable through member references
)
case prefix: NamedType =>
(!sym.is(Private) && prefix.derivesFrom(sym.owner)) ||
(!prefix.symbol.moduleClass.isStaticOwner && isInteresting(prefix.prefix))
!sym.is(Private) && prefix.derivesFrom(sym.owner)
|| {
val pcls = prefix.symbol.moduleClass
if pcls.isStaticOwner then
pcls.span.exists && pcls.defRunId == ctx.runId // cheaper approximation to isDefinedInCurrentRun
else
isInteresting(prefix.prefix)
}
case SuperType(thistp, _) => isInteresting(thistp)
case AndType(tp1, tp2) => isInteresting(tp1) || isInteresting(tp2)
case OrType(tp1, tp2) => isInteresting(tp1) && isInteresting(tp2)
Expand All @@ -329,15 +335,27 @@ object Checking {
case _ => false
}

if (isInteresting(pre)) {
val pre1 = this(pre, false, false)
if (locked.contains(tp) || tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter])
throw CyclicReference(tp.symbol)
locked += tp
try if (!tp.symbol.isClass) checkInfo(tp.info)
finally locked -= tp
tp.withPrefix(pre1)
}
if isInteresting(pre) then
val traceCycles = CyclicReference.isTraced
try
if traceCycles then
CyclicReference.pushTrace("explore ", tp.symbol, " for cyclic references")
val pre1 = this(pre, false, false)
if locked.contains(tp)
|| tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter]
then
throw CyclicReference(tp.symbol)
locked += tp
try
if tp.symbol.isOpaqueAlias then
checkInfo(TypeAlias(tp.translucentSuperType))
else if !tp.symbol.isClass then
checkInfo(tp.info)
finally
locked -= tp
tp.withPrefix(pre1)
finally
if traceCycles then CyclicReference.popTrace()
else tp
}
catch {
Expand Down Expand Up @@ -374,7 +392,11 @@ object Checking {
*/
def checkNonCyclic(sym: Symbol, info: Type, reportErrors: Boolean)(using Context): Type = {
val checker = withMode(Mode.CheckCyclic)(new CheckNonCyclicMap(sym, reportErrors))
try checker.checkInfo(info)
try
val toCheck = info match
case info: RealTypeBounds if sym.isOpaqueAlias => TypeAlias(sym.opaqueAlias)
case _ => info
checker.checkInfo(toCheck)
catch {
case ex: CyclicReference =>
if (reportErrors)
Expand Down
74 changes: 52 additions & 22 deletions tests/neg/i15507.check
Original file line number Diff line number Diff line change
@@ -1,40 +1,70 @@
-- Error: tests/neg/i15507.scala:2:40 ----------------------------------------------------------------------------------
2 | type _NestedSet1[X] = Set[_NestedSet1[?]] // error
-- Error: tests/neg/i15507.scala:3:40 ----------------------------------------------------------------------------------
3 | type _NestedSet1[X] = Set[_NestedSet1[?]] // error
| ^
| no wildcard type allowed here
-- Error: tests/neg/i15507.scala:3:41 ----------------------------------------------------------------------------------
3 | type _NestedSet2[X] <: Set[_NestedSet2[?]] // error
-- Error: tests/neg/i15507.scala:4:41 ----------------------------------------------------------------------------------
4 | type _NestedSet2[X] <: Set[_NestedSet2[?]] // error
| ^
| no wildcard type allowed here
-- [E140] Cyclic Error: tests/neg/i15507.scala:5:7 ---------------------------------------------------------------------
5 | type _NestedSet4[X] >: Set[_NestedSet4[X]] // error
-- [E140] Cyclic Error: tests/neg/i15507.scala:6:7 ---------------------------------------------------------------------
6 | type _NestedSet4[X] >: Set[_NestedSet4[X]] // error
| ^
| illegal cyclic type reference: lower bound ... of type _NestedSet4 refers back to the type itself
-- [E140] Cyclic Error: tests/neg/i15507.scala:6:7 ---------------------------------------------------------------------
6 | type _NestedSet5[X] = Set[_NestedSet5[X]] // error
|
| The error occurred while trying to compute the signature of type _NestedSet4
| which required to explore type _NestedSet4 for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i15507.scala:7:7 ---------------------------------------------------------------------
7 | type _NestedSet5[X] = Set[_NestedSet5[X]] // error
| ^
| illegal cyclic type reference: alias ... of type _NestedSet5 refers back to the type itself
-- [E140] Cyclic Error: tests/neg/i15507.scala:7:7 ---------------------------------------------------------------------
7 | type _NestedSet6[X] = Set[_NestedSet6[Int]] // error
|
| The error occurred while trying to compute the signature of type _NestedSet5
| which required to explore type _NestedSet5 for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i15507.scala:8:7 ---------------------------------------------------------------------
8 | type _NestedSet6[X] = Set[_NestedSet6[Int]] // error
| ^
| illegal cyclic type reference: alias ... of type _NestedSet6 refers back to the type itself
-- Error: tests/neg/i15507.scala:9:43 ----------------------------------------------------------------------------------
9 | type _NestedList1[X] = List[_NestedList1[?]] // error
| ^
| no wildcard type allowed here
-- Error: tests/neg/i15507.scala:10:44 ---------------------------------------------------------------------------------
10 | type _NestedList2[X] <: List[_NestedList2[?]] // error
|
| The error occurred while trying to compute the signature of type _NestedSet6
| which required to explore type _NestedSet6 for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- Error: tests/neg/i15507.scala:10:43 ---------------------------------------------------------------------------------
10 | type _NestedList1[X] = List[_NestedList1[?]] // error
| ^
| no wildcard type allowed here
-- Error: tests/neg/i15507.scala:11:44 ---------------------------------------------------------------------------------
11 | type _NestedList2[X] <: List[_NestedList2[?]] // error
| ^
| no wildcard type allowed here
-- [E140] Cyclic Error: tests/neg/i15507.scala:12:7 --------------------------------------------------------------------
12 | type _NestedList4[X] >: List[_NestedList4[X]] // error
-- [E140] Cyclic Error: tests/neg/i15507.scala:13:7 --------------------------------------------------------------------
13 | type _NestedList4[X] >: List[_NestedList4[X]] // error
| ^
| illegal cyclic type reference: lower bound ... of type _NestedList4 refers back to the type itself
-- [E140] Cyclic Error: tests/neg/i15507.scala:13:7 --------------------------------------------------------------------
13 | type _NestedList5[X] = List[_NestedList5[X]] // error
|
| The error occurred while trying to compute the signature of type _NestedList4
| which required to explore type _NestedList4 for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i15507.scala:14:7 --------------------------------------------------------------------
14 | type _NestedList5[X] = List[_NestedList5[X]] // error
| ^
| illegal cyclic type reference: alias ... of type _NestedList5 refers back to the type itself
-- [E140] Cyclic Error: tests/neg/i15507.scala:14:7 --------------------------------------------------------------------
14 | type _NestedList6[X] = List[_NestedList6[Int]] // error
|
| The error occurred while trying to compute the signature of type _NestedList5
| which required to explore type _NestedList5 for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i15507.scala:15:7 --------------------------------------------------------------------
15 | type _NestedList6[X] = List[_NestedList6[Int]] // error
| ^
| illegal cyclic type reference: alias ... of type _NestedList6 refers back to the type itself
|
| The error occurred while trying to compute the signature of type _NestedList6
| which required to explore type _NestedList6 for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
1 change: 1 addition & 0 deletions tests/neg/i15507.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//> using options -explain-cyclic
object TestNested:
type _NestedSet1[X] = Set[_NestedSet1[?]] // error
type _NestedSet2[X] <: Set[_NestedSet2[?]] // error
Expand Down
50 changes: 50 additions & 0 deletions tests/neg/i19372.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
-- [E140] Cyclic Error: tests/neg/i19372.scala:3:7 ---------------------------------------------------------------------
3 | type AAA = List[bar.BBB] // error: cyclic
| ^
| illegal cyclic type reference: alias List[Test1.bar.BBB] of type AAA refers back to the type itself
|
| The error occurred while trying to compute the signature of type AAA
| which required to explore type BBB for cyclic references
| which required to explore type AAA for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i19372.scala:9:7 ---------------------------------------------------------------------
9 | type A = bar.B // error: cyclic
| ^
| illegal cyclic type reference: alias Test2.bar.B of type A refers back to the type itself
|
| The error occurred while trying to compute the signature of type A
| which required to explore type B for cyclic references
| which required to explore type A for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i19372.scala:15:7 --------------------------------------------------------------------
15 | type AAA = List[bar.BBB] // error: cyclic
| ^
| illegal cyclic type reference: alias List[Test3.bar.BBB] of type AAA refers back to the type itself
|
| The error occurred while trying to compute the signature of type AAA
| which required to explore type BBB for cyclic references
| which required to explore type AAA for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i19372.scala:21:7 --------------------------------------------------------------------
21 | type A = bar.B // error: cyclic
| ^
| illegal cyclic type reference: alias Test4.bar.B of type A refers back to the type itself
|
| The error occurred while trying to compute the signature of type A
| which required to explore type B for cyclic references
| which required to explore type A for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
-- [E140] Cyclic Error: tests/neg/i19372.scala:30:7 --------------------------------------------------------------------
30 | type UCharIteratorReserved = Ptr[UCharIterator] // error: cyclic
| ^
|illegal cyclic type reference: alias Ptr[structs.UCharIterator] of type UCharIteratorReserved refers back to the type itself
|
|The error occurred while trying to compute the signature of type UCharIteratorReserved
| which required to explore type UCharIterator for cyclic references
| which required to explore type UCharIteratorReserved for cyclic references
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
38 changes: 38 additions & 0 deletions tests/neg/i19372.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//> using options -explain-cyclic
object Test1:
type AAA = List[bar.BBB] // error: cyclic
def foo: AAA = ???
object bar:
opaque type BBB = AAA

object Test2:
type A = bar.B // error: cyclic
def foo: A = ???
object bar:
opaque type B = A

object Test3:
type AAA = List[bar.BBB] // error: cyclic
def foo: AAA = ???
object bar:
type BBB = AAA

object Test4:
type A = bar.B // error: cyclic
def foo: A = ???
object bar:
type B = A

trait Ptr[T]

object aliases:
import structs.*
type UCharIteratorReserved = Ptr[UCharIterator] // error: cyclic
object UCharIteratorReserved:
def iterator: UCharIterator = ???

object structs:
import aliases.{*, given}
opaque type UCharIterator = Ptr[UCharIteratorReserved]
object UCharIterator:
def reservedFn: UCharIteratorReserved = ???
47 changes: 3 additions & 44 deletions tests/neg/i8984.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import scala.annotation.tailrec
type |@[F[+_], G[+_]] = [a] =>> F[a] | G[a]

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

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

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

object ApplyFix:
Expand All @@ -18,44 +18,3 @@ object Fix:

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

final case class Cat[+R](name: String, fur: String, rest: R)
object Cat:
def of[R, F[+_]](name: String, fur: String, rest: Fix[F]): Fix[F |@ Cat] = Fix(new Cat(name, fur, rest))

final case class Dog[+R](name: String, size: Long, rest: R)
object Dog:
def of[R, F[+_]](name: String, size: Long, rest: Fix[F]): Fix[F |@ Dog] = Fix(new Dog(name, size, rest))

case object End:
type f[+a] = End.type
def apply() = Fix[f](End)

object DropRed:
@tailrec def dropRedCats[F[+a] >: Cat[a]](cats: Fix[F]): Fix[F] =
cats.value match
case Cat(_, "red", rest) => dropRedCats(rest) // error
case _ => cats

type CatDogVector = Vector[Either[Cat[Unit], Dog[Unit]]]
type CatOrDogs[+a] = Cat[a] | Dog[a] | End.type

extension (catDogs: Fix[CatOrDogs]) def toVector : CatDogVector =
@tailrec def go(acc: CatDogVector, catDogs: Fix[CatOrDogs]) : CatDogVector = catDogs.value match
case Cat(name, fur, rest) => go(acc :+ Left(Cat(name, fur, ())), rest)
case Dog(name, size, rest) => go(acc :+ Right(Dog(name, size, ())), rest)
case End => acc

go(Vector(), catDogs)

val x =
Cat.of("lilly" , "red" ,
Cat.of("anya" , "red" ,
Cat.of("boris" , "black",
Dog.of("mashka", 3 ,
Cat.of("manya" , "red" ,
End())))))


def main(args: Array[String]) =
println(x.toVector)
println(dropRedCats(x).toVector)