On January 30, 2025, the first Scala Tooling Spree took place, and I had the pleasure of being part of it. Here’s a recap of the event. Spoiler alert: it was awesome!

Event details

The first Scala Tooling Spree was announced on Discord and Bluesky. The event brought together 9 participants who formed 4 teams. Over the course of a 2-hour call, we tackled 4 issues, resulting in 3 pull requests. We had participants with diverse backgrounds, ranging from business application developers to tooling and compiler engineers. Each team had at least one experienced tooling maintainer, ensuring we were never short on expertise!

As for the technical aspect of the meeting, it was very well organized! Before the meeting, participants were divided into teams with an issue assigned to each. After an ice breaker, we were invited to breakout rooms where we discussed the problems and pair-programmed the solutions. After around 90 minutes, we returned to the main room to share our results.

What we worked on

For the first Scala Tooling Spree we were able to solve 3 out of 4 selected issues during the meeting, which I think is an amazing result. Here’s a quick summary of the results

Extract code action should support fewer braces syntax #7138

I can tell most about this one, as I had a pleasure to work on it together with Tomasz Godzik.

The issue was about code action for extracting values not working correctly with fewer braces syntax. Provided you had a code like:

//> using scala 3

import scala.util.Try

def main =
  val x = Try:
    Some(new Exception)

When you selected Some(new Exception) in your IDE and executed “extract value” code action, it would produce following output:

//> using scala 3

import scala.util.Try

def main =
  val newValue = :
    Some(new Exception)
  val x = Try(newValue)

You can notice the : which clearly is an invalid syntax. To fix this we added a simple heuristic that verifies if the block we are extracting starts with : and refine the value in such cases.

It was a great opportunity to learn about code actions in Metals, and the fix was surprisingly simple!

Full solution: https://github.com/scalameta/metals/pull/7164

Disclaimer I only worked on the issue above, so I might not be 100% correct about the details of the issues below

Insert type breaks compilation when using symbolic methods #7122

This was an issue with a twist. Originally reported in Scalafix #2166 it was suspected to be caused by Metals in #7122.

The original issue said that when using Scalafix with following config:

rules = [
  ExplicitResultTypes
]

A snippet like this:

object A {
  def ! = 1.to(10).map(i => i -> i.toString()).toMap
}

Gets converted to:

object A {
  def !: Map[Int, String] = 1.to(10).map(i => i -> i.toString()).toMap
}

This is invalid, because !: is treated as an expression. There should be a space in between the characters for the compiler to understand such method.

It’s an issue with a twist, because the fix (at least for Scala 3 case) ended up landing in the compiler itself!

See following PR https://github.com/scala/scala3/pull/22485 for the solution

Support compiled .class files as inputs #1642

This was the one we weren’t able to solve. In short, the idea is to enable scala-cli users to provide single .class files for compilation and execution, skipping the --classpath option.

This has proven to be more complicated than anticipated, so instead of providing the solution the team wrote down their issue analysis in the issue comments.

Check out the discussion in https://github.com/VirtusLab/scala-cli/issues/1642

Go to implementation doesn’t work with self types #3808

The last issue to be worked on was about code navigation. Provided you have a following code:

trait A { def aa: Unit }
trait B{
 this : A =>
  override def aa: Unit = ()
}

Executing “go to implementation” on aa in the first line wouldn’t work. This didn’t work because the implementation was scoped in a self type. The fix for this issue was done in ImplementationProvider (which is a kind of SemanticdbFeatureProvider) in the lookup logic.

The solution is still a draft, you can find it in: https://github.com/scalameta/metals/pull/7170

Bonus feature: Convert sbt style deps on paste in for scala-cli #7176

Because the issue we worked on was an easy fix, we still had some time to spend. We decided to look at code action for converting sbt dependencies within scala-cli code (see #5078) to make it also work on paste.

The implementation was as easy as implementing a short class extending RangeFormatter and plugging it into RangeFormattingProvider for Metals to know to execute it on paste. The code for rewriting dependency format was already there, so we just reused it.

See the PR for full implementation https://github.com/scalameta/metals/pull/7176

Join us next time!

The Scala Tooling Spree was a great opportunity to learn about the inner workings of the tools I use daily. It’s a unique chance to get comfortable with the codebase, gain exposure to a different kind of code architecture (compared to business applications), and feel empowered to contribute your own bugfixes and features in the future.

Let’s not overlook the social side of things: meeting fellow Scala enthusiasts and the welcoming, hard-working team behind Metals was truly a highlight.