scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.85k stars 1.06k forks source link

Cyclic reference error when refering to an implicit parameter from another implicit parameter's type #18258

Open Sporarum opened 1 year ago

Sporarum commented 1 year ago

Compiler version

3.3.0 / 3.3.1-RC1

Minimized code & Ouptut

class myAnnot(s: String) extends scala.annotation.Annotation

trait Showable[A]

def show[A : Showable](x: A) = x.toString

def f1(using Showable[Int])(otherParam: Int @myAnnot(show[Int](4))) = ???

def f2(using Showable[Int])(using otherParam: Int @myAnnot(show[Int](4))) = ??? // error: Cyclic reference involving implicit parameter otherParam

Expectation

Either both methods should compile, or neither of them should

As I don't see any cyclic reference with otherParam, I assume the correct fix is to make f2 succeed

This also has implications for the following:

def f3[A](x: A)(using shower: Showable[A], otherParam: Int @myAnnot(show[A](x))) = ??? // error: Cyclic reference involving implicit parameter otherParam

def f4[A : Showable](x: A)(using otherParam: Int @myAnnot(show[A](x))) = ??? // error: Cyclic reference involving implicit parameter otherParam

(f4 surprisingly desugars to f3: https://docs.scala-lang.org/scala3/reference/contextual/context-bounds.html#)

Sporarum commented 1 year ago

The error seems self-contained enough for a spree, and might offer an interesting tour of rare parts of the compiler

Sporarum commented 1 year ago

Might be related to: https://github.com/lampepfl/dotty/issues/17242 https://github.com/lampepfl/dotty/issues/17224

mbovel commented 3 months ago

This issue was picked for the Scala Issue Spree of tomorrow, July 2nd. @mbovel and @jan-pieter will be working on it! If you have any insight into the issue or guidance on how to fix it, please leave it here.

mbovel commented 3 months ago

Reproduced.

Let tests/pos/18258.scala be:

class myAnnot(s: String) extends scala.annotation.Annotation
trait Showable[A]
def f(using Showable[Int])(using otherParam: Unit @myAnnot(summon[Showable[Int]](4))) = ???

sbt:scala3> scalac -explain-cyclic tests/pos/18258.scala
[info] running (fork) dotty.tools.dotc.Main -d /Users/mbovel/dotty/compiler/../out/default-last-scalac-out.jar -classpath /Users/mbovel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.14/scala-library-2.13.14.jar:/Users/mbovel/dotty/library/../out/bootstrap/scala3-library-bootstrapped/scala-3.5.1-RC1-bin-SNAPSHOT-nonbootstrapped/scala3-library_3-3.5.1-RC1-bin-SNAPSHOT.jar -explain-cyclic tests/pos/18258.scala
-- [E047] Cyclic Error: tests/pos/18258.scala:3:65 -----------------------------
3 |def f(using Showable[Int])(using otherParam: Unit @myAnnot(summon[Showable[Int]](4))) = ???
  |                                                                 ^
  |Cyclic reference involving implicit parameter otherParam
  |
  |The error occurred while trying to compute the signature of method f
  |  which required to compute the signature of parameter otherParam
  |  which required to searching for an implicit argument of type Showable[Int]
  |  which required to compute the signature of parameter otherParam
  |
  | Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
  |
  | longer explanation available when compiling with `-explain`
mbovel commented 3 months ago

Further minimized thanks to @EugeneFlesselle:

class myAnnot(s: Int) extends scala.annotation.Annotation
def f(using otherParam: Unit @myAnnot(summon[Int])) = ???

So it seems otherParam is in the implicit scope when typechecking the argument of @myAnnot.

Arguably, it should not?

Sporarum commented 3 months ago

This can also be minimized like so:

class myAnnot(s: Int) extends scala.annotation.Annotation

given String @myAnnot(summon[Int]) = "" // error: Cyclic reference involving val given_String

In that case it seems even more dubious that it should see itself.

Both these cases are also surprising, as the type of the given/using is different from the one of the summon, so there is no recursion going on !