diff --git a/_data/scala-releases.yml b/_data/scala-releases.yml index 31ee6ab4c..16f30b4b0 100644 --- a/_data/scala-releases.yml +++ b/_data/scala-releases.yml @@ -1,7 +1,7 @@ - category: current_version - title: Current 3.6.x release - version: 3.6.4 - release_date: March 7, 2025 + title: Current 3.7.x release + version: 3.7.0 + release_date: May 7, 2025 - category: current_version title: Current 3.3.x LTS release version: 3.3.5 diff --git a/_downloads/2025-05-07-3.7.0.md b/_downloads/2025-05-07-3.7.0.md new file mode 100644 index 000000000..3b00aac94 --- /dev/null +++ b/_downloads/2025-05-07-3.7.0.md @@ -0,0 +1,10 @@ +--- +title: Scala 3.7.0 +start: 7 May 2025 +layout: downloadpage +release_version: 3.7.0 +release_date: "May 7, 2025" +permalink: /download/3.7.0.html +license: Apache License, Version 2.0 +api_docs: https://www.scala-lang.org/api/3.7.0/ +--- diff --git a/_posts/2025-05-07-release-notes-3.7.0.md b/_posts/2025-05-07-release-notes-3.7.0.md new file mode 100644 index 000000000..c980d2959 --- /dev/null +++ b/_posts/2025-05-07-release-notes-3.7.0.md @@ -0,0 +1,522 @@ +--- +category: release +permalink: /news/3.7.0/ +title: "Scala 3.7.0 released!" +by: Wojciech Mazur, VirtusLab +--- + +![Scala 3.7]({{ site.baseurl }}/resources/img/scala-3.7-launch.png) + +We're excited to announce the release of Scala 3.7.0 — a significant minor release that brings stabilized SIPs, powerful new features, expanded platform support, and notable improvements to tooling and compatibility. + +# What’s new in Scala 3.7? + +## Stabilised SIPs + +The [Scala Improvement Process (SIP)](https://docs.scala-lang.org/sips/) is how language changes and additions are made. + + +### [SIP-58: Named Tuples](https://docs.scala-lang.org/sips/named-tuples.html) + +Named Tuples, introduced as experimental in Scala 3.5, are now a stable feature. +Named tuples are a convenient lightweight way to return multiple results from a function or to model the data using tuples while allowing you to use meaningful names for its fields. + +```scala +@main def meaningfullReturnTypes = + extension [T](seq: Seq[T]) + inline def partitionBy(predicate: PartialFunction[T, Boolean]): (matching: Seq[T], unmatched: Seq[T]) = + seq.partition(predicate.unapply(_).getOrElse(false)) + + List( + (x = 1, y = 0), + (x = 2, y = 3), + ).partitionBy: + case (x = x, y = 0) => x < 5 + .matching.map(_.x) + .foreach(println) + + val measurements = List[(location: String, value: Double)]( + ("Lausanne", 8.05), + ("London", 21), + ("Rome", 37.0), + ) + val average = measurements.map(_.value).sum / measurments.size +``` + +What's more, this feature also enhances existing features. For example, it is now possible to match on a subset of case class fields by name. By doing so you no longer need to specify a long list of wildcard selectors for each field of a large case class. + +```scala +@main def selectiveClassExtractors = + case class Order( + id: String, + createdAt: OffsetDateTime, + shippedAt: Option[OffsetDateTime] = None, + deliveredAt: Option[OffsetDateTime] = None, + itemIds: List[String] = Nil + ) + + val orders = List.empty[Order] + val selected = orders.collect: + case Order(id = s"special-${internalId}", shippedAt = None) => internalId + case Order(id = orderId, itemIds = items) if items.size > 5 => orderId +``` + +Last, but not least, named tuples are opening a new technique in metaprogramming by letting you compute structural types without the need for macros! +The `Selectable` trait now has a `Fields` type member that can be instantiated to a named tuple. + +```scala +class QueryResult[T](rawValues: Map[String, Any]) extends Selectable: + type Fields = NamedTuple.Map[NamedTuple.From[T], Option] + def selectDynamic(fieldName: String) = rawValues.get(fieldName) + +case class Release(version: String, issues: List[String]) + +@main def Test = + val query: QueryResult[Release] = QueryResult(Map("version" -> "3.7.0")) + val version: Option[String] = query.version + assert(query.version.contains("3.7.0")) + assert(query.issues.isEmpty) +``` + +### [SIP-52: Binary APIs](https://docs.scala-lang.org/sips/binary-api.html) + +For library maintainers, Scala 3.7.0 stabilizes the `@publicInBinary` annotation, introduced experimentally in Scala 3.4. This annotation ensures binary compatibility when inline methods access non-public members and prevents generation of redundant accessors required by inlining mechanism. + +Inline methods are always inlined at their call sites. If they refer to members not visible outside their defining scope, the compiler generates accessor methods. The accessors are not subject to binary compatibility; they might be emitted differently by newer versions of compiler or eventually removed. +The `@publicInBinary` annotation addresses this by emitting those members as public in bytecode, while maintaining restricted source-level visibility. + This allows the compiler to refer to the original non-private member without the need to create additional accessors. + +```scala +object api: + class Service: + private[api] def implementation(): Unit = println("Executing old API") + inline def use() = implementation() + // generated by compiler, accessed in `use()` + // def api$Service$$inline$implementation(): Unit = implementation() + + class Consumer: + inline def consume() = api.Service().implementation() + // generated by compiler, accessed in `consume()` + // def inline$implementation$i1(x$0: api$Service) = x$0.implementation() + + @scala.annotation.publicInBinary + private[api] var isActive: Boolean = false + inline def isStale = !isActive +``` + +The new annotation also resolves a long-standing issue with the inability to invoke a private constructor of a class from inlined methods. Now by annotating the constructor with `@publicInBinary` you are allowed to access it directly from inlined methods. + +```scala +import scala.annotation.publicInBinary + +class Printer @publicInBinary private(id: Int) +object Printer: + inline def create(): Printer = new Printer(42) // Not allowed previously +``` + +SIP-52 has also introduced the linting flag `-WunstableInlineAccessors` which detects and emits warnings for all unstable accessors generated for inline methods. This flag has been available since Scala 3.4.0. We highly recommend its usage of users' codebases, especially in the case of public libraries. + +## Preview features + +Scala 3.7 introduces the concept of `preview` features — fully implemented and SIP-approved, but potentially subject to small refinements before becoming stable. +New Scala language features or standard library APIs are initially introduced as experimental, but once they become fully implemented and accepted by the [SIP](https://docs.scala-lang.org/sips/) these can become a "preview" feature. + +Preview language features and APIs are guaranteed to be standardized in some future Scala minor release, but allow the compiler team to introduce small, possibly binary incompatible, changes based on community feedback. +These can be used by early adopters who can accept the possibility of binary compatibility breakage. For instance, preview features could be used in an application or internal tool. On the other hand, preview features are discouraged in publicly available libraries. + +All preview features can be enabled together using the new `-preview` compiler option. More information about preview features can be found in [preview definitions guide](https://docs.scala-lang.org/scala3/reference/preview/overview.html) + +### [SIP-62: For comprehension improvements](https://docs.scala-lang.org/sips/better-fors.html) + +The first preview feature is [SIP-62 - `Better Fors`](https://docs.scala-lang.org/sips/better-fors.html), originally added to Scala 3.6 as experimental. +A major user-facing improvement introduced by this SIP is the ability to start a for-comprehension block with assignment (for example, `a = 1`). +It also introduces changes to how some `for` comprehensions are desugared by the compiler, avoiding redundant calls, for better code. + +```scala +//> using options -preview +//> using scala 3.7 +@main def betterFors = + for + a = 1 + b <- Some(2) + c = a * b + yield c +``` + +The code above previously required `a` to be defined outside the for-comprehension block. Additionally, it was introducing redundant allocations and method calls to correctly handle possible `if` guards. In result it would have desugared to following code: + +```Scala + Some(2) + .map { b => + val c = a * b + (b, c) + }.map { case (b, c) => c } +``` + +With SIP-52 the same snippet would be desugared to simpler and more efficent code: + +```Scala + Some(2).map { b => + val c = a * b + c + } +``` + +We encourage users to try out this feature which is likely going to be stabilised in Scala 3.8. + +## New experimental features + +### [SIP-61: Unroll Default Arguments for Binary Compatibility](https://docs.scala-lang.org/sips/unroll-default-arguments.html) + +Some library maintainers have long avoided case classes in public APIs, since any change to their fields affected binary compatibility. This was typically observed whenever a new field was added to the case class primary constructor, even if it was defined with a default value to resolve source compatibility problems. Though such binary incompatibilities were detected by [MiMa](https://github.com/lightbend/mima), avoiding them required manually creating shim methods to match the old signatures. + +The `@unroll` annotation will eliminate this long-standing issue. This annotation lets you add additional parameters to method `def`s, `class` constructors, or `case class`es, without breaking binary compatibility. `@unroll` works by generating unrolled or “telescoping” forwarders, ensuring your code will remain binary compatible as new default parameters and fields are added over time. + +```scala +//> using scala 3.7 +//> using options -experimental + +import scala.annotation.unroll + +case class Product( + name: String, + price: BigDecimal, + @unroll description: Option[String] = None, +){ + // generated by compiler: + // def this(name: String, price: BigDecimal) = this(name, price, default$1) + // def copy(name: String, price: BigDecimal) = this(name, price) +} + +object Factory: + def processOrder( + products: List[Product], + @unroll quantity: Int = 1, + @unroll discount: Int = 0 + ): Unit = ??? + + // generated by the compiler: + // def processOrder(products: List[Product]): Unit = processOrder(products, default$1, default$2) + // def processOrder(products: List[Product], quantity: Int): Unit = processOrder(products, quantity, default$2) +``` + +More details can be found in [`@unroll` reference](https://docs.scala-lang.org/scala3/reference/experimental/unrolled-defs.html) + +### [SIP-68: Reference-able Package Objects](https://github.com/scala/improvement-proposals/pull/100) + +One limitation with `package object`s is that we cannot directly refer to them as values, even though that is possible for normal `object`s. Such references can already be made with a special ".`package`" accessor, but this is ugly and non-obvious. Or one could use a normal `object`, which is not always possible. + +The SIP drops this limitation, allowing such direct references. + +```scala +//> using scala 3.7 +//> using options -experimental + +package my.pkg +import scala.language.experimental.packageObjectValues + +package object releases: + val `3.7` = "3.7.0" + +@main def referencablePkgObject = + val versions = my.pkg.releases + val oldStyle = my.pkg.releases.`package` + println(versions eq oldStyle) // prints true +``` + +For more details visit the [reference page](https://docs.scala-lang.org/scala3/reference/experimental/package-object-values.html) for this feature. + +## Other notable changes + +### New scheme for given prioritization + +In the [Scala 3.5.0 release notes](https://scala-lang.org/blog/2024/08/22/scala-3.5.0-released.html) we announced upcoming changes to givens, to improve their prioritization. Under the old rules, the compiler always tried to select the instance with the most specific subtype of the requested type. Under the new rules, it always selects the instance with the most general subtype that satisfies the context bound. +Starting with Scala 3.7, the compiler uses the new behavior by default. +Running the compiler with `-source:3.5` will allow you to temporarily keep using the old rules. +Under `-source:3.7-migration`, code whose behaviour differs between new and old rules (ambiguity on new, passing on old, or vice versa) will emit warnings, but the new rules will still be applied. + +For detailed motivation of the changes, with examples of code that will be easier to write and understand, see our 2024 blog post - [Upcoming Changes to Givens in Scala 3.7]({{ site.baseurl }}/2024/08/19/given-priority-change-3.7.html). + +### Expression Compiler is now part of Scala 3 compiler ([#22597](https://github.com/scala/scala3/pull/22597)) + +The expression compiler powers the debug console in Metals and the IntelliJ Scala plugin, enabling the evaluation of arbitrary Scala expressions at runtime (even macros). The expression compiler produces class files that can be loaded by tooling to compute the evaluation output. +Previously expression compiler was developed independently from the Scala compiler inside [scalacenter/scala-debug-adapter](https://github.com/scalacenter/scala-debug-adapter) repository and was cross-published for every Scala release. +Starting with Scala 3.7 the expression compiler has been migrated to the main [scala/scala3](https://github.com/scala/scala3) repository and become an integral part of Scala toolchain. This change allows users to use the expression compiler with nightly versions of the compiler as well, easing the maintenance and release process for the compiler team. + +### Presentation Compiler: Show inferred type on holes in hover ([#21423](https://github.com/scala/scala3/pull/21423)) + +The presentation compiler is a special mode of the Scala compiler that runs interactively and is used by IDEs and language servers such as Metals. It provides immediate feedback about code correctness, type checking, symbol resolution, autocompletion, error highlighting, and other editing support functionalities. +Some of the latest improvements to the presentation compiler focus on the ability to infer more information about expected types of expressions provided by the users. As a result, presentation compiler can now show the users the expected type of expression when hovering over so called `type holes`. + +```scala +def someMethod(count: Int, label: String): Unit = ??? +someMethod(???, ???) +``` + +Given the code snippet above, hovering on either placeholder will hint about the expected type (`Int` and `String`, respectively). + +### Quotes API changes + +Scala 3.7 introduces changes to the experimental subset of Quotes API. One notable addition is the `apply` methods to import selectors ([#22457](https://github.com/scala/scala3/pull/22457)), allowing to dynamically construct import statements within macros. This feature can be especially useful when summoning implicit instances in the generated code, as it allows to add additional instances to the search​. + +Another advancement is the experimental `summonIgnoring` method ([#22417](https://github.com/scala/scala3/pull/22417)). It allows developers to summon implicit instances while excluding specific instances of givens from the search. It's particularly useful in complex derivation scenarios where certain implicit should be disregarded to prevent conflicts or unintended resolutions.​ It might be used to provide a custom implementation of macro only in cases where a user-defined variant of implicit is available, while avoiding recursively re-calling the macro method. + +```scala +//> using options -experimental + +import scala.quoted.* + +trait ExcludedType +trait Show[T]: + def show(): Unit + +object Show { + transparent inline given auto[T]: Show[T] = ${ autoImpl[T] } + + private def autoImpl[T: Type](using Quotes): Expr[Show[T]] = + import quotes.reflect.* + Expr.summonIgnoring[Show[ExcludedType]]( + // Ignore implicits produced by these symbols: + Symbol.classSymbol("Show").companionModule.methodMember("auto")* + ) match + case Some(instance) => + // User provided their own instance of `Show[ExcludedType]` - use it + '{ + new Show[T]: + def show(): Unit = + println(s"Show[${${ Expr(TypeRepr.of[T].show) }}] including user defined Show[ExcludedType]:") + $instance.show() + } + case None => + // No user-defined implicit for `Show[ExcludedType]` beside `Show.auto` + '{ + new Show[T]: + def show(): Unit = + println(s"Show[${${ Expr(TypeRepr.of[T].show) }}]") + } +} +``` + +Furthermore, the experimental `Symbol.newClass` method has been extended to support class parameters, flags, privateWithin, and annotations ([#21880](https://github.com/scala/scala3/pull/21880)). This enhancement enables the dynamic creation of classes with constructors, access modifiers, and annotations, providing greater control over generated code structures. With those changes included, we are planning to stabilize this method (and `ClassDef.apply`) soon. + +### Improvements to `-Wunused` and `-Wconf` ([#20894](https://github.com/scala/scala3/pull/20894)) + +Scala 3.7 introduces a significant enhancement to its linting mechanism by revamping the `CheckUnused` compiler phase. Previously, developers encountered false-positive warnings when importing givens, particularly when they were defined in shared traits across multiple objects. This issue often led to unnecessary code restructuring or the disabling of linting checks.​ + +The updated implementation leverages the `MiniPhase` API, aligning the linting process more closely with the compiler's contextual understanding. This change ensures that the compiler accurately identifies genuinely unused imports, thereby reducing misleading warnings. +Additionally, the update introduces support for `-Wunused:patvars`, enabling warnings for unused pattern variables. +Changes also enhance the `-Wconf` option to allow origin-based filtering `-Wconf:origin=full.path.selector` as in Scala 2. That allows, for example, to exclude certain blessed imports from warnings, or to work around false positives: + +```scala +-Wconf:origin=scala.util.chaining.given:s +``` + +These improvements collectively provide developers with more precise and configurable linting tools, enhancing code quality and maintainability.​ + +### Implicit parameters now warn at call site without `using` keyword ([#22441](https://github.com/scala/scala3/pull/22441)) + +As part of Scala's ongoing migration from `implicit` to the newer, clearer `given` and `using`, Scala 3.7 introduces a change regarding method calls involving implicit parameters. Now, explicitly providing arguments to methods defined with `implicit` warns if the call site doesn't say `using`. This adjustment reduces ambiguity inherent in Scala 2 syntax, where it was unclear whether an explicitly provided argument was intended for an implicit parameter or for the apply method of the resulting object. + +```scala +trait Config +object Config: + def default: Config = ??? + +def implicitBased(implicit config: Config) = ??? +def givenBased(using Config) = ??? + +@main def explicitImplicits = + implicitBased(Config.default) // warning: Implicit parameters should be provided with a `using` clause. + implicitBased(using Config.default) // recommended + + givenBased(Config.default) // error: Would not compile without `using`` + givenBased(using Config.default) +``` + +Scala 3.7 provides an automated migration path for existing codebases through the compiler flags -rewrite -source:3.7-migration, which automatically inserts the recommended `using` keywords, streamlining the transition to the new syntax. +Users of Scala 2 can introduce the `using` syntax at callsite into their codebase as well. The implicit based example above would successfully compile when using at least Scala 2.12.17 or Scala 2.13.9 without any additional flags. + +### Scala 3 unblocked on Android ([#22632](https://github.com/scala/scala3/pull/22632)) + +Scala 3.7 brings a crucial fix that enhances its compatibility with the Android platform. Previously, developers faced issues when compiling Scala 3 code for Android due to the Android Runtime (ART) enforcing stricter type constraints on lambdas than the standard Java Virtual Machine (JVM). Specifically, ART requires that the return type of a Single Abstract Method (SAM) interface be a primitive type or explicitly boxed, a condition not mandated by the JVM.​ + +The update addresses this by modifying the Scala compiler to box the return type of native instantiated methods when the SAM's return type isn't primitive. This change ensures that lambda expressions conform to ART's expectations, preventing runtime errors on Android devices. By aligning the compiler's behaviour with ART's requirements, the Scala 3 development for the Android platform should be unblocked, although it might require recompiling existing libraries using Scala 3.7 or the upcoming Scala 3.3 LTS version containing a backported fix. + +### Support for dependent case classes ([#21698](https://github.com/scala/scala3/pull/21698)) + +Case classes may now have dependent fields, improving expressiveness and type safety. This allows fields within a case class to depend on other constructor parameters via path-dependent types. One use case is encoding a configuration system where each setting has a distinct value type determined by the setting itself. + +```scala +case class ConfigEntry(option: Setting, default: option.Value): + def value(using Context): option.Value = option.userDefined.getOrElse(default) + +trait Context +trait Setting(val name: String): + type Value + def userDefined(using Context): Option[Value] = None + +class StringSetting(name: String) extends Setting(name): + override type Value = String + +class IntSetting(name: String) extends Setting(name): + override type Value = Int + + +@main def DependentCaseClasses = + given Context = new {} + val settings = List[ConfigEntry]( + ConfigEntry(StringSetting("docs.page"), "https://docs.scala-lang.org/"), + ConfigEntry(IntSetting("max.threads"), 32) + ) +``` + +This enhancement simplifies type-safe heterogeneous collections and makes it easier to express advanced design patterns previously requiring workarounds or more verbose type definitions. + +Be aware of some pattern matching limitations for dependent case classes - the types of the extracted components are currently approximated to their non-dependent upper-bound: + +```scala +trait A: + type B <: AnyRef + +case class CC(a: A, b: a.B) +object Test: + def foo(cc: CC) = cc match + case CC(a, b) => + // `a` has type `A` + // `b` has type `AnyRef` instead of the more precise `a.B` +``` + +### REPL: bring dependencies in with `:jar` ([#22343](https://github.com/scala/scala3/pull/22343)) + +It is now possible to bring new dependencies to an already running REPL session with the `:jar` command. It is effectively the equivalent of Scala 2’s `:require`. + +For example, for a given simple example: + +```scala +// example.scala +object Message: + val hello = "Hello" +``` + +After packaging it into a JAR: + +```bash +scala package example.scala --power --library +# Compiling project (Scala 3.7.0, JVM (24)) +# Compiled project (Scala 3.7.0, JVM (24)) +# Wrote example.jar +``` + +It's possible to bring it into a running REPL session like this: + +```scala +Welcome to Scala 3.7.0(23.0.1, Java OpenJDK 64-Bit Server VM). +Type in expressions for evaluation. Or try :help. + +scala> :jar example.jar +Added 'example.jar' to classpath. + +scala> Message.hello +val res0: String = Hello +``` + +### Dependency updates + +#### Scala 2 Standard Library + +Scala 3 now uses the [Scala 2.13.16](https://github.com/scala/scala/releases/tag/v2.13.16) standard library. Be mindful of these breaking changes and deprecations since 2.13.15: + +* On the empty string, `.tail` and `.init` now throw (instead of returning the empty string) [#10851](https://github.com/scala/scala/pull/10851) +* Do not use `rangeHash` when `rangeDiff` is 0 [#10912](https://github.com/scala/scala/pull/10912) +* Deprecate `collection.mutable.AnyRefMap` [#10862](https://github.com/scala/scala/pull/10862) + +#### Scala.js + +Scala.js has been updated from version 1.16.0 to 1.19.0. +Libraries published using Scala 3.7 must use Scala.js 1.19.0 or later. +Please refer to Scala.js changelogs for more details: + +* [Scala.js 1.17.0](https://www.scala-js.org/news/2024/09/28/announcing-scalajs-1.17.0) +* [Scala.js 1.18.1](https://www.scala-js.org/news/2025/01/09/announcing-scalajs-1.18.1) +* [Scala.js 1.18.2](https://www.scala-js.org/news/2025/01/23/announcing-scalajs-1.18.2) +* [Scala.js 1.19.0](https://www.scala-js.org/news/2025/04/21/announcing-scalajs-1.19.0) + +#### Scala CLI + +The Scala runner has been updated to Scala CLI 1.7.1. + +Notable changes include: + +* The `fmt` sub-command now uses `scalafmt` binaries built with Scala Native. This change can improve the performance of formatting Scala sources. +* (⚡️ experimental) Support for running `scalafix` rules has been added to the `fix` sub-command. + +Please refer to Scala CLI changelogs for more details: + +* [Scala CLI 1.6.0](https://github.com/VirtusLab/scala-cli/releases/tag/v1.6.0) +* [Scala CLI 1.6.1](https://github.com/VirtusLab/scala-cli/releases/tag/v1.6.1) +* [Scala CLI 1.7.0](https://github.com/VirtusLab/scala-cli/releases/tag/v1.7.0) +* [Scala CLI 1.7.1](https://github.com/VirtusLab/scala-cli/releases/tag/v1.7.1) + +# What’s next? + +With the final release of Scala 3.7.0, the first patch version [3.7.1-RC1](https://github.com/scala/scala3/releases/tag/3.7.1-RC1) has already been made available. This release includes additional fixes and improvements introduced after the branch cutoff. + +Looking ahead, you can expect at least two more patch releases before Scala 3.8, which is scheduled for September 2025. The goal for Scala 3.8 is to be the last minor version before the next Long-Term Support (LTS) release, Scala 3.9, which is planned for early 2026. + +The Scala compiler team aims to finalize all major changes in 3.8, followed by a soft feature freeze and a stabilization period. This ensures a smooth transition for users and maximizes the stability of the compiler and tooling ecosystem ahead of the LTS release. + +# Contributors + +Thank you to all the contributors who made this release possible 🎉 + +According to `git shortlog -sn --no-merges 3.6.4..3.7.0` these are: + +``` + 63 Martin Odersky + 47 Som Snytt + 33 Adrien Piquerez + 32 Hamza Remmal + 29 Wojciech Mazur + 19 aherlihy + 19 kasiaMarek + 16 Jan Chyb + 13 Dale Wijnand + 11 Kacper Korban + 10 EnzeXing + 9 Sébastien Doeraene + 7 Guillaume Martres + 7 Matt Bovel + 7 Oliver Bračevac + 7 noti0na1 + 5 HarrisL2 + 5 Jamie Thompson + 5 dependabot[bot] + 4 Joel Wilsson + 4 Piotr Chabelski + 4 Seth Tisue + 3 Roman Janusz + 3 anna herlihy + 2 David Hua + 2 Tomasz Godzik + 2 Yichen Xu + 1 Alec Theriault + 1 Daisy Li + 1 Daniel Thoma + 1 Dmitrii Naumenko + 1 Felix Herrmann + 1 He-Pin(kerr) + 1 João Ferreira + 1 Jędrzej Rochala + 1 Katarzyna Marek + 1 Kenji Yoshida + 1 Natsu Kagami + 1 Niklas Fiekas + 1 Rocco Mathijn Andela + 1 Vadim Chelyshov + 1 adpi2 + 1 fan-tom + 1 philwalk + 1 rochala +``` + +For a full list of changes and contributor credits, please refer to the [release notes](https://github.com/scala/scala3/releases/tag/3.7.0). diff --git a/resources/img/scala-3.7-launch.png b/resources/img/scala-3.7-launch.png new file mode 100644 index 000000000..11e285dab Binary files /dev/null and b/resources/img/scala-3.7-launch.png differ