Improving the compilation error reporting of sbt

That is a good question. Sometimes I do use IntelliJ’s build function, but sometimes but sometimes I don’t, because:

  • it’s less easy to do a clean build (doesn’t have a keyboard shortcut or button), but it’s easy to make a run configuration for sbt clean compile
  • some of my projects support 2.11 and 2.12, and IntelliJ only builds for scalaVersion in your build.sbt (or at least, I don’t know how to configure it to build for all versions).
  • I often like to run tests as well, which IntelliJ will only run for the primary Scala version (which may miss a test failure for 2.12.0 if scalaVersion is 2.12.2
  • occasionally sbt shows fewer errors for a particular root cause (e.g. only 2 errors to look at for the single cause, instead of 4)

It would be more correct to say that sometimes I use sbt to check, and sometimes IntelliJ’s build function.

While admitting quite frankly that the initial IntelliJ sbt support was pretty much unusable; I have to say it’s vastly improved today.

Two reasons in my case

  • The compiler mess with each other classes so running the compiler from intellij then from sbt (or vice versa) will lead the second one to do a full compile and mess with the one which was 1st before. This is especially painful when using play’s dev mode on a largish project

  • sbt compile will only compile “production code” not test code and I can easily restrict compilation to the single module I am working on (and go fix the rest later), while intellij will always try to compile everything including all the tests scopes and all the modules which can be a major pain.

I really wish both compilers would not step on each other’s toes … I can’t wait for sbt 1.0 and sbt server to finally get rid of this issue.

2 Likes

I’m just going to throw in a comment as an educator who uses Scala in entry level classes. I don’t use sbt early on. The real benefit of Scala in CS1 is that it has the ability to run as scripts. I know that education isn’t always high on the list of users to consider for these things, but for us, the improved messages will only be beneficial when they get into the normal compiler. Granted, figuring out how to do them in sbt could be a very good way to learn how to do them in the compiler.

I’ve discussed this with @Duhemm, @lrytz, and @dwijnand, and here’s the summary of my view.

First, I want to thank Martin for initiating this discussion and proposing an implementation. I am sympathetic to the idea of improving the command-line user interface via various means. I’ve done my share of that including sbt-slash proposal, sbt-doge, having a better prompt etc. We should continue to discuss the pros/cons and improvements we can make in the error reporting.

Second aspect of this proposal that seems to be taking over this thread is the topic of where and when we should make this change. As sbt 1.0 has gone into RC cycle, we will not be able to accept this feature as part of sbt 1.0. There are certainly breakages due to removal of archaic syntax and addition of Zinc and LM APIs, but we intend to minimize the jump between sbt 0.13 and sbt 1.0, not add more attractions. This principle applies also to my own proposal for unified slash syntax (sbt-slash), which we decided to release as sbt 0.13 plugin to test its stability and usability instead of including it to sbt 1.0:

There’s also been concerns around introducing this change late in the game, so after discussing with Dale, we decided to introduce this as a form of a plugin.

Precisely because of the wide usage of sbt (by humans or otherwise), I don’t think we should treat sbt as a means of sidestepping the validation by Adriaan’s team. If we have community’s support for Martin’s change, the roadmap should lead to upstream contribution to the Scala compiler. I think sbt plugin is a great way to experiment and iterate these types of things, and we can help socializing the plugin. Once there are community support around the proposal (or some subset of it), Lightbend Scala team should be open to adding that feature into Scala 2.12 and 2.13.

5 Likes

Yes, that is currently the idea. (I am the person who works on sbt support in IDEA). I can’t make any promise as to how soon this will happen however, considering there are plenty of other open issues for sbt. If any issue is particularly interesting to you, I encourage you to vote on it.

2 Likes

I think this is a very worthwhile effort. Interesting question whether to put it directly in scalac or sbt. Having suffered through the atrocious way scalac error messages are rendered by the Eclipse IDE, I think we should go for some abstraction here. Ideally, the compiler should issue error messages in some easily consumable format that can be rendered by frontends as appropriate. The format might be textual itself, or not.

So, can we think of a “message beautifier” that can be added to either sbt or scalac? (or any other frontend?) That would leave core scalac free to generate messages in an easily parsable no-frills format but would still provide the UI benefits in both SBT and raw scalac.

5 Likes

There are standard formats for error reporting in, eg Emacs (see flycheck). It would be good to have that available in scala in addition to the sbt output.

From our (Emacs) perspective, the workflow of being able to run a command and have it marked up (e.g. clickable links with shortcut commands to the error line / column) is exceptionally productive (a standard feature across all languages) and not something I want to lose (the recent efforts, although well intentioned, have threatened this workflow). Having a way to be able to extract further info (e.g. full range positions) to overlay on the text screen would be a win.

Although, having said all that… I’d trade it all in for better reporting when an implicit can’t be found. e.g. for generic derivation.

The compiler already supports Reporter interface that Zinc abstracts. The reporter reports each compilation warning/error as Problem datatype. This is customizable from sbt via compilerReporter setting, which is what @Duhemm did in his sbt plugin.

sbt server also uses it to turn compiler errors into JSON messages, which other tools can listen into.

So, we have a lot of things set up to iterate on this. That’s why I remain optimistic on this discussion.

2 Likes

My 2 cents as an end user:

I’ve been working with Typescript a lot. And having an “language service” api on the compiler/build tool that’s used by all IDEs / text editors is an awesome development experience. The exact same, correct, fast behaviour in your IDE & CLI build.
To me it feels that that is the inevitable way forward for editors to integrate with build tools/compilers.

So I was wondering: what if sbt would provide such a build service first and deal with useability of errors and provide them to the outside and later when that kind of service is available from scalac/dotty editors can switch if they want. Because there’s a stable api.

Of course that would predicate on Emacs moving to using that kind of language service instead of scanning CLI formatting. (I guess that’s a step they’ll probably have to take at some point anyway.)

As I said: just my 2 cts.

ps as a grizzled backend developer I cheer on any initiatives that make Scala less intimidating to newcomers.
I remember explaining to an experienced Java developer how hard to analyse for loops with mutable variables are. But that we just didn’t realise that any more.
Probably we experienced Scala devs don’t see a lot of accidental complexity anymore as well. :slight_smile:

2 Likes

Agreed. But that one is a bit harder to do…

1 Like

I wonder how much of Martin’s code is actually depending on sbt? If it’s not too much it could help if the better error reporting could live as a standalone library (for now) with a connector to sbt so that other tools might also be able to benefit from it.

When it comes to the UI (like actual formatting of messages) it would be worthwhile to get all the improvements into scalac itself but that shouldn’t prevent anyone from experimenting and bootstrapping that effort aside from the compiler for now. Just merging back the UI parts into the compiler should be simple enough even later on. On the other hand, the question is if e.g. json export should live in scalac at all or if that should be provided in a third-party library even later on.

I haven’t looked into error reporting for a long time (but I did experiments earlier, with improving implicits reporting and also with another never published sbt plugin that provided an interactive UI to group errors by all kinds of criteria which helped me keeping an overview while porting a code base with hundreds of compiler errors). Back then one big problem was, that error messages from scalac were mostly text based and semantic details had to be reconstructed or were lost completely. The most important improvement in scalac itself would be to provide better structured error messages so that other tools don’t have to really on parsing error messages in the first place.

Part of this thread seems to have been spent on which tool is the most used interface to compiler’s error messages. I’ve come to the conclusion that there currently is no clear answer to that question. It seems there are several different, popular ways how people get exposed to error messages. There are also different requirements for different use cases (for example, I haven’t used the interactive error browser tool for years because that porting effort was a one-time effort, but back then it was very useful).

The best short-term outcome could be different cooperating initiatives:

  • a library with tools that improve the error output from scalac
  • a connector that brings these capabilities to sbt
  • any kind of improvements that can only be done in scalac that help consuming error messages and providing better structured information
2 Likes

Is there any documentation on how other apps (like IDE/editor plugins) can connect and interact with the sbt server?

Heh. Oh I can imagine. Ironically, I just lost the morning to this because I thought there was a bug in shapeless generic derivation of sealed abstract classes… but … just turned out to be I didn’t have a typeclass instance for FiniteDuration.

I like that there are initiatives such as GitHub - tek/splain: better implicit errors for scala but it unfortunately didn’t help me this time around. Maybe with an intelligent filter of the implicit searches I know to be dead ends would be good (e.g. especially where I hack it to support subtypes via <:< evidence).

Or maybe this just all gets fixed by accident when Miles’ inductive implicits supports Lazy (or the => syntax) for recursive types.

What would you like the compiler to report if no suitable implicit is found?

After all, the compiler can’t tell whether you were trying to do something
that was supposed to work, but you forgot to provide some evidence that it
does, or whether you were trying to do something that is not supposed to
work.

it sounds like a deficiency in shapeless derivation macro, eg the macro from play-json reports missing instances quite legibly
my experiments with shapeless for play format derivation seem to demonstrate it https://scastie.scala-lang.org/OlegYch/TObLxa2kSqujBCk3HUgWMQ

The compiler currently only reports the top level implicit than could not be resolved, not the thing that caused the entire tree to fail. Play has not addressed this, their messages are comparable to shapeless.

I have an example in the spray-json-shapeless tests, under assertions for messages during failed compilation. Perhaps you could try to derive the same tree and report back the error.