Easing debugging for macros

Hello,
Following the Scala 3, macro annotations and code generation discussion,
it seems like it would be worthwhile to give users a simple way to see what code is being generated (by everything, not just macro annotations)

Hence my two ideas/questions:

Do we currently have a user-friendly way of displaying generated code (maybe as a diff ?)

If yes, then we should include reference to it when there is an error that arises inside a macro, so the user is nudged towards using it (they might even have no idea it exists)

PS: We have to think about a solution that scales to big files

3 Likes

For typing errors this is done (with -explain flag enabled): added to type mismatch reporting output of tree, which can't be typed by rssh · Pull Request #12717 · lampepfl/dotty · GitHub
Maybe can be generalized to the other types of errors, if you have an example.

But it only shows the tree local to the error, right ?

This is already really nice, but some cases might require a more thorough look at the generated code more globally

I don’t have a specific example handy, but for example in cases where macros call macros which call macros, it might be difficult to tell the context, since the snippet you are shown by the compiler will probably be fully automatically generated.
Said differently, in cases like this the compiler will show you code which has no common element with the content of the file.

1 Like

I think there is an option in IntelliJ to see the generated code. We could probably do something similar on top of LSP by emitting a “debug” report in the compiler. I think something like that is done by quill, which reports an “info” message containing the generated SQL query: Scastie - An interactive playground for Scala..

Currently, scastie (and any LSP-based IDE, I guess?) displays that “report” with something you can click to in the margin:
Screenshot from 2022-12-20 09-50-56
When you click, you see the generated SQL query:
Screenshot from 2022-12-20 09-50-46

2 Likes

If the generated code is large, this is not very practical

I think I’m advocating for the following:
A simple command that creates a diff file where the deleted lines are the initial macro calls, the added lines the inside (recursively) of the macros, and the unchanged lines everything else

The advantage are that:

  • IDEs tend to have very good diff support
  • It would be possible to have something like the “Open preview on the side” as is done for markdowns
  • scales to large files

But maybe my premise is flawed in that having a solution that scales well will encourage people to make big macros

1 Like

Not sure if this would even be possible via LSP, but something like what IntelliJ does for implicit lookup would be really nice.

You’d have the actual code and something to click/mouse-over/interact with that shows the first level of generated code, and anything in that code which triggers another macro is similarly annotated so you can look at the high-level situation and then drill down into just the parts you are interested in.

One situation where this would be really handy is if you’ve got a situation like this:

val foo = explicitMacroTrigger()

Which expands to something like this:

val foo = bar(
  macroTriggerThatExpandsToAnAbsoluteWallOfCodeThatWorksAsExpected(),
  macroTriggerYouAreDebugging(),
  macroTriggerThatExpandsToAnAbsoluteWallOfCodeThatWorksAsExpected()
)
3 Likes