Is your feature request related to a problem? Please describe.
There is known issue related to difference in experience when you work with project that successfully compiled errors vs when there are some compilation errors.
Most of Metals feature rely on having .class and semanticdb directories. So if compilation fails they can't be updated and we unable to provide the actual state of sources. This affects all important features like completions, hover, go to definition and many others.
Examples that I would like to see working are:
- it will be possible to clone a fresh project with compilation error but able to work with it immediately, instead of manually suppressing errors (commenting code or putting
???)
- it will be possible break the code but continue entering new symbols and they will be visible for PC:
// initial st
/a/src/main/scala/A.scala
object A {
def foo: Int = 42
}
/a/src/main/scala/B.scala
object B {
val x = A.foo
}
// introduce an error
/a/src/main/scala/A.scala
object A {
def foo: Int = "sadsad" // error
}
/a/src/main/scala/B.scala
object B {
val x = A.foo
}
// lets' say you are doing dome refactoring and decided that
// to fix `B.x` you need a new object C
/a/src/main/scala/A.scala
object A {
def foo: Int = "sadsad" // error
}
/a/src/main/scala/C.scala
object C {
def newFoo: Int = ???
}
/a/src/main/scala/B.scala
object B {
val x = C.@@ // <- here we should get completions `newFoo`
}
- the same example above should also support the case when there are several build targets and the error is in upstream one
Describe the solution you'd like
I've already did some investigation and PoC for fixing the thing I described.
However, now I don't have enough time to complete it. @tgodzik asked me to share the existing state.
So, in general the idea is that we have to compile as much as possible and produce signatures instead of classfiles + semanticdb to a special directory.
It was never a case for existing scala-tooling but it probably it's the only option that might fit the existing Metals architecture.
Here I will describe how the solution of this might work and share my PoC branches.
- New flag to compiler - produce signatures and cleanup errors from tress where it's possible
- Scala 3
PoC changes - scala/scala3@428256d
For Scala3 I added -Yinteractive-trees-path compiler flag which:
- forces the compiler to continue phases until
pickler ignoring errors
- at
pickler phase cleanup trees from errors
- writes these trees into
.tasty files in a special directory (value of -Yinteractive-trees-path)
Also, it allows to load classpath only from .tasty files. Right now, compiler loads them only if there is .class file.
- Scala 2
Before experimenting with scala 3 For I did a similar thing for Scala 2 but using compiler-plugin - https://github.com/dos65/metals/tree/sigcompiler. There I was using .sig files instead of tasty but overall the approach was similar to above one.
- Bsp - a special directory for signatures + continue compilation using
signatures dir
Here is a commit that adds --interactive flag for CompileRequest in bloop. It allows, to continue compilation even is upstream project has errors. Also, in case of Metals, bloop adds signatures which will be passed as -Y-interactive-trees-path to compiler.
Changes into build-server-protocol - build-server-protocol/build-server-protocol@de19a05
-
Last part - changes in Metals
Metals should be adapted to use this signaturesDir directory instead of outputDirectory as classpath for PC.
Also, it should reload PC every time compilation completes even in case of having errors.
I haven't completed PoC for metals but here is my wip changes - dos65/metals@376f890
I also, should notice, that reloading PC every time might cause performance issues and probably this approach would require some incremental PC reloading. However, for this thing I have no ideas how it might be done and which changes will be required (probably something inside compiler for symbol table reloading)
Describe alternatives you've considered
As some of us might remember, in some issues there were mentions of -Youtline compiler option and that this one might solve this issue. I've tried it but doesn't fully fit for fixing this issue because compiler won't be forced to dump .sig files if there were error at parser stage + it only ignores blocks, and bodies.
// signature ok - `A` + `A.foo` will be provided
class A {
def foo: Int = "asdsada" // error
}
// no signatures - typer error
class B extends Unknown { // error: not found Unknown
def foo: Int = ???
}
Additional context
Search terms
compiler, tasty, semanticdb, bsp, presentation compiler
Is your feature request related to a problem? Please describe.
There is known issue related to difference in experience when you work with project that successfully compiled errors vs when there are some compilation errors.
Most of Metals feature rely on having
.classandsemanticdbdirectories. So if compilation fails they can't be updated and we unable to provide the actual state of sources. This affects all important features like completions, hover, go to definition and many others.Examples that I would like to see working are:
???)Describe the solution you'd like
I've already did some investigation and PoC for fixing the thing I described.
However, now I don't have enough time to complete it. @tgodzik asked me to share the existing state.
So, in general the idea is that we have to compile as much as possible and produce signatures instead of classfiles + semanticdb to a special directory.
It was never a case for existing scala-tooling but it probably it's the only option that might fit the existing Metals architecture.
Here I will describe how the solution of this might work and share my PoC branches.
PoC changes - scala/scala3@428256d
For Scala3 I added
-Yinteractive-trees-pathcompiler flag which:picklerignoring errorspicklerphase cleanup trees from errors.tastyfiles in a special directory (value of-Yinteractive-trees-path)Also, it allows to load classpath only from
.tastyfiles. Right now, compiler loads them only if there is.classfile.Before experimenting with scala 3 For I did a similar thing for Scala 2 but using compiler-plugin - https://github.com/dos65/metals/tree/sigcompiler. There I was using
.sigfiles instead of tasty but overall the approach was similar to above one.signaturesdirHere is a commit that adds
--interactiveflag forCompileRequestin bloop. It allows, to continue compilation even is upstream project has errors. Also, in case of Metals, bloop addssignatureswhich will be passed as-Y-interactive-trees-pathto compiler.Changes into build-server-protocol - build-server-protocol/build-server-protocol@de19a05
Last part - changes in Metals
Metals should be adapted to use this
signaturesDirdirectory instead ofoutputDirectoryas classpath for PC.Also, it should reload PC every time compilation completes even in case of having errors.
I haven't completed PoC for metals but here is my wip changes - dos65/metals@376f890
I also, should notice, that reloading PC every time might cause performance issues and probably this approach would require some incremental PC reloading. However, for this thing I have no ideas how it might be done and which changes will be required (probably something inside compiler for symbol table reloading)
Describe alternatives you've considered
As some of us might remember, in some issues there were mentions of
-Youtlinecompiler option and that this one might solve this issue. I've tried it but doesn't fully fit for fixing this issue because compiler won't be forced to dump.sigfiles if there were error at parser stage + it only ignores blocks, and bodies.Additional context
Search terms
compiler, tasty, semanticdb, bsp, presentation compiler