-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Cyclic errors when using exports #17076
Comments
Could this be related to the incremental compilation? |
@doofin when you get the error, have you tried to compile it manually from the terminal? Just to see if the error happens in general or within the current state of bloop. |
I tried to compile with sbt manually (I have also clean/cleanFiles before compile) , and it's the same error I feel it might be related to incremental compilation, but this scenario seems to suggest it's more than that trying to search for "Overloaded or recursive constructor"(does that imply type constructors needs kind annotation?) gives no result in dotty codebase,there's only "Overloaded or recursive methods". |
@doofin would it be possible for you to provide the entire codebase of the project (assuming it's not confidential)? If not then maybe you could try creating a copy of the project and gradually removing portions of code until the problem stops occurring? |
thanks @smarter to help me pinpoint the problem, it happens when some methods are not explicitly given type annotations like below: extension [w <: Int](x: Expr[w]) {
def +(oth: Expr[w]) = BinOp(x, oth, "+")
def *(oth: Expr[w]) = BinOp(x, oth, "*")
def -(oth: Expr[w]) = BinOp(x, oth, "-")
def |(oth: Expr[w]) = BinOp(x, oth, "|")
def &(oth: Expr[w]) = BinOp(x, oth, "&")
} However, I copied this snippet to another project but still can't reproduce it. Will meet with @smarter for possible better error message when this happens. |
Hi @prolativ I tried but it might be a bit hard to reduce it to minimul. The project might be open sourced in the future but is currently private. I have invited you to the project and feel free to take a look at doofin/dependentChisel@101cf6d |
I can reproduce the errors with: object A {
import B.*
def foo(foo: Foo[Int]) = foo
}
object B {
import C.*
trait Expr[T <: Int]
case class Foo[T <: Int](x: Any) extends Expr[T]
def foo = Foo(0)
}
object C extends D.Foo[Int](0)
object D {
export B.*
} -- Error: try/i17076/A.scala:9:30 ----------------------------------------------
9 | case class Foo[T <: Int](x: Any) extends Expr[T]
| ^^^
| Something's wrong: missing original symbol for type tree
-- [E044] Cyclic Error: try/i17076/A.scala:9:2 ---------------------------------
9 | case class Foo[T <: Int](x: Any) extends Expr[T]
| ^
| Overloaded or recursive constructor Foo needs return type The use of |
@smarter I spent a few hours yesterday minimizing that and I almost got to this point but you turned out to be faster 😆 |
Minimized slightly further:
object A {
def bar(x: B.Foo[Int]) = x
}
object B {
import C.*
case class Foo[T <: Int](x: Any)
def foo = Foo(0)
}
object C extends D.Foo[Int](0)
object D {
export B.foo
type Foo[T <: Int] = B.Foo[T]
} |
We clearly should not complain about a missing return type in a constructor. We should fall back to the generic "cyclic reference involving...." error message instead. That said, this looks like a legit cyclic reference error, no?
There's your cycle. |
FWIW I think cyclic errors should be displayed like your comment (including "There's your cycle" ;) ) |
Yes, this would be great! I don't yet see an easy way to do it, though. Essentially, the compiler would have to keep a log of everything it does which would have to be inspected in case of a Cyclic Reference. That looks expensive, in both time and code complexity... |
I don't think recording all steps the compiler takes would be necessary, wouldn't we just need the steps that the cyclic reference check does? Couldn't this be done in a similar way to zio 2.x's stack reification? If you're unfamiliar with it, basically it tries to make progress recursively in a try catch block (it looks like the implementation for checking cyclic references is already doing this) and if it needs to yield, it throws a ReifyStack exception which contains a ChunkBuilder. This is caught at every level of recursion, adding the effect to the ChunkBuilder and rethrowing the ReifyStack exception. When it gets to the first try/catch, the exception contains the whole stack which is turned into a chunk and sent back to the scheduler. I think a similar approach may be used here which means basically no overhead unless there's a cyclic error. Do you think this approach may be feasible or am I missing something here? |
We do similar stack reification when we emit "a recurring operation is" diagnostics. But we can't directly use it for cyclic references (at least not as a default) since we are not allowed to unwind the stack to the root of the problem. Instead, we continue reporting close to where the cyclic reference was detected. |
This is a very strange problem that only shows occasionally, I have no idea how to reliably reproduce it.
updates: reproduced in #17076 (comment) and #17076 (comment)
Compiler version
3.2.2
Minimized code
it can't be reproduced,that's why it's so strange. I copied this snippet to another project without giving any errors.
Output
metals ide gives error below,and sbt also gives same error message:
the error message is
Sometimes, it will give errors like "Cyclic reference involving val ..."
Expectation
code should compile
The text was updated successfully, but these errors were encountered: