question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unexpected `Illegal cyclic reference` error since Scala 3.1.2

See original GitHub issue

Problem found when migrating sangria to Scala 3.

Compiler version

3.1.3-RC4 Runs correctly in 3.1.1, broken since 3.1.2, dottyCompileBisect gave me 40ae7eee109a3c8a3a125c1ec4a2167bba2acd9c as the first bad commit and 3.1.2-RC1-bin-20211217-b3ab102-NIGHTLY as the first bad release.

Minimized code

Problematic code:

//> using scala "3.1.3-RC4"

import scala.annotation.implicitNotFound

sealed trait Tagged[U]
type @@[+T, U] = T with Tagged[U] // intersection type seems to be the culprit, compiles if removed

@implicitNotFound(
  "Type ${Val} cannot be used as an input. Please consider defining an implicit instance of `FromInput` for it.")
trait FromInput[Val]

private object ScalarFromInput extends FromInput[Any] {}

implicit def coercedScalaInput[T]: FromInput[T @@ CoercedScalaResult] =
  ScalarFromInput.asInstanceOf[FromInput[T @@ CoercedScalaResult]]

implicit def optionInput[T](implicit ev: FromInput[T]): FromInput[Option[T]] = { // inline here fixes the issue
  ev.asInstanceOf[FromInput[Option[T]]]
}

trait CoercedScalaResult

sealed trait InputType[+T]

trait WithoutInputTypeTags[T] {
  type Res
}

object WithoutInputTypeTags {
  implicit def coercedArgTpe[T]: WithoutInputTypeTags[T @@ CoercedScalaResult] { type Res = T } =
    new WithoutInputTypeTags[T @@ CoercedScalaResult] {
      type Res = T
    }

  implicit def coercedOptArgTpe[T]
      : WithoutInputTypeTags[Option[T @@ CoercedScalaResult]] { type Res = Option[T] } =
    new WithoutInputTypeTags[Option[T @@ CoercedScalaResult]] {
      type Res = Option[T]
    }
}

case class OptionInputType[T](ofType: InputType[T]) extends InputType[Option[T]]

case class ScalarType[T](name: String) extends InputType[T @@ CoercedScalaResult]

val BooleanType: ScalarType[Boolean] = ScalarType[Boolean]("Boolean")

case class Argument[T](
  name: String, // seemingly important argument for this issue, compiles without it
  argumentType: InputType[_],
  fromInput: FromInput[_]
)

object Argument {
  inline def apply[T](name: String, argumentType: InputType[T])(implicit // inline here makes no difference, added for MacroHelp
      fromInput: FromInput[T],
      res: WithoutInputTypeTags[T]): Argument[res.Res] = { // returned type seems to be the issue here
    println(MacroHelp.showType[T]) // added for debugging
    Argument(name, argumentType, fromInput)
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    Argument("name", OptionInputType(BooleanType)) :: Nil // List.apply works correctly but still infers weird
  }
}

Macro I added to check inferred types:

import scala.quoted._
object MacroHelp {
  inline def showType[T] = ${showTypeImpl[T]}

  def showTypeImpl[T](using Quotes)(using t: Type[T]): Expr[String] = {
    import quotes.reflect.*
    val tpe = TypeRepr.of[T].show
    Expr(tpe)
  }
}

Output

[error] ./Cyclic.scala:66:52: Recursion limit exceeded.
[error] Maybe there is an illegal cyclic reference?
[error] If that's not the case, you could also try to increase the stacksize using the -Xss JVM option.
[error] A recurring operation is (inner to outer):
[error] 
[error]   subtype Tagged[CoercedScalaResult] <:< T
[error]     Argument("name", OptionInputType(BooleanType)) :: Nil // List.apply works correctly but still infers weird
[error]  

Expectation

The code should compile and run, like it does in 3.1.1. I added a macro that shows that inside of Argument.apply type T is inferred as scala.Option[Cyclic$package.@@[scala.Nothing, CoercedScalaResult] & Tagged[CoercedScalaResult]], whereas in scala 3.1.1 it was scala.Option[Test2$package.@@[scala.Any, CoercedScalaResult] & Tagged[CoercedScalaResult]]. However, my intuition tells me that the type should be scala.Option[Cyclic$package.@@[scala.Boolean, CoercedScalaResult]]]. It is also worth noting that since the code originally comes from Scala 2, the previously-compound-now-intersection type does not work like it did there, where it was possible to cast T to T @@ Tagged[SomeOtherType] - an operation on which Sangria’s internal type system relies heavily. Since that does not work as well, I imagine I will have to slightly rethink the api there for Scala 3, which may (or may not) make this issue less important. There are a lot of factors that make the problem appear and I had trouble minimizing code further, so I tried to add comments showing how things affect each other.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
griggtcommented, Jun 4, 2022

Bisecting the original example shows 3ab18a90ac24dba440c498aab6a8f0c763589605 from #14026 as the first bad commit.

Unlike the original example, the minimized one fails to compile with 3.1.1.

They both fail to compile on latest nightly 3.2.0-RC1-bin-20220602-42b5941-NIGHTLY.

0reactions
oderskycommented, Nov 15, 2022

Need to re-open because of #16344

Read more comments on GitHub >

github_iconTop Results From Across the Web

What is and why is the fault that creates the Illegal cyclic ...
A specific reason in Scala (ignoring the ontological implications of having a cycle in the inheritance graph) is that the constructor for a ......
Read more >
Bug listing with status UNCONFIRMED as at 2022/12/19 13 ...
Bug :128538 - "sys-apps/coreutils: /bin/hostname should be installed from coreutils ... circular dependencies" status:UNCONFIRMED resolution: severity:normal ...
Read more >
A Study of Typing-Related Bugs in JVM Compilers
Some of our representative findings are: (1) most of fixed typing-related bugs (50.94%) manifest as unexpected compile-time errors: the buggy compiler ...
Read more >
Compilation fails (incorrectly) with "Illegal Cyclic References ...
Compilation fails (incorrectly) with "Illegal Cyclic References" when package objects are involved until rebuild/FSC reset ; Project, Scala ; Subsystem, Compiler.
Read more >
Bug List - Bugs - Eclipse
IllegalStateException when closing efxclipse application, 2014-10-01 ... NOT_, Git perspective is not showing up inside Eclipse after installing EGit plugin ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found