Open
Description
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.
sealed trait Expr[w <: Int]
case class BinOp[w <: Int](a: Expr[w], b: Expr[w], nm: String) extends Expr[w]
Output
metals ide gives error below,and sbt also gives same error message:
the error message is
Overloaded or recursive constructor BinOp needs return type
Something's wrong: missing original symbol for type tree
Sometimes, it will give errors like "Cyclic reference involving val ..."
Expectation
code should compile
Activity
nicolasstucki commentedon Mar 10, 2023
Could this be related to the incremental compilation?
nicolasstucki commentedon Mar 10, 2023
@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.
doofin commentedon Mar 10, 2023
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".
prolativ commentedon Mar 10, 2023
@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?
doofin commentedon Mar 13, 2023
thanks @smarter to help me pinpoint the problem, it happens when some methods are not explicitly given type annotations like below:
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.
doofin commentedon Mar 16, 2023
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
smarter commentedon Mar 16, 2023
I can reproduce the errors with:
The use of
object C extends D.Foo[Int](0)
is arguably problematic since we importC.*
in the scope where we defineFoo
itself, but there isn't anything equivalent in the original codebase, so there's probably still something missing to trigger the problem in the same way it's triggered in the original codebase.[-]Something's wrong: missing original symbol for type tree[/-][+]Cyclic errors when using exports[/+]prolativ commentedon Mar 17, 2023
@smarter I spent a few hours yesterday minimizing that and I almost got to this point but you turned out to be faster 😆
prolativ commentedon Mar 17, 2023
Minimized slightly further:
trait Expr
import B.*
odersky commentedon Apr 25, 2023
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?
B.foo
.B.foo
.B.Foo
B.Foo
you need to analyze the importimport C.*
(for instance, it might define a typeInt
, which would take precedence overscala.Int
.C
.C
you need to analyze its parent,D.Foo
D
.D
you need to analyze the export.There's your cycle.
bertlebee commentedon May 21, 2023
FWIW I think cyclic errors should be displayed like your comment (including "There's your cycle" ;) )
odersky commentedon May 22, 2023
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...
bertlebee commentedon May 22, 2023
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?
odersky commentedon May 22, 2023
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.