Skip to content

Commit

Permalink
refactor: Migrate Metals server to Scala 3
Browse files Browse the repository at this point in the history
This mostly involved:
- changing imports
- moving things between MtagsEnrichements variants
- adding ()
- fixing bugs reported now as warning or errors (things previously not reported at all)
  • Loading branch information
tgodzik committed Dec 20, 2023
1 parent d596f64 commit 1f4dabb
Show file tree
Hide file tree
Showing 221 changed files with 1,098 additions and 1,054 deletions.
10 changes: 2 additions & 8 deletions .scalafix.conf
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
rules = [
OrganizeImports,
ExplicitResultTypes,
RemoveUnused
OrganizeImports
]

ExplicitResultTypes.rewriteStructuralTypesToNamedSubclass = false

RemoveUnused.imports = false

OrganizeImports.groupedImports = Explode
OrganizeImports.expandRelative = true
OrganizeImports.removeUnused = true
OrganizeImports.removeUnused = false
OrganizeImports.groups = [
"re:javax?\\."
"scala."
Expand Down
19 changes: 19 additions & 0 deletions .scalafix2.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
rules = [
OrganizeImports,
ExplicitResultTypes,
RemoveUnused
]

ExplicitResultTypes.rewriteStructuralTypesToNamedSubclass = false

RemoveUnused.imports = false

OrganizeImports.groupedImports = Explode
OrganizeImports.expandRelative = true
OrganizeImports.removeUnused = true
OrganizeImports.groups = [
"re:javax?\\."
"scala."
"scala.meta."
"*"
]
13 changes: 0 additions & 13 deletions .scalafix3.conf

This file was deleted.

3 changes: 2 additions & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version = "3.7.17"
runner.dialect = scala213
runner.dialect = scala3
project.git = true
align.preset = none
align.stripMargin = true
Expand Down Expand Up @@ -34,6 +34,7 @@ fileOverride {
},
"glob:**/mtags*/**" {
trailingCommas = never
runner.dialect = scala213
}
"glob:**/tests/cross/src/**" {
trailingCommas = never
Expand Down
121 changes: 76 additions & 45 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ def crossSetting[A](
logo := Welcome.logo
usefulTasks := Welcome.tasks

ThisBuild / scalafixScalaBinaryVersion := scalaBinaryVersion.value
ThisBuild / scalafixScalaBinaryVersion := "2.13"

inThisBuild(
List(
version ~= { dynVer =>
if (isCI) dynVer
else localSnapshotVersion // only for local publishing
},
scalaVersion := V.scala213,
crossScalaVersions := List(V.scala213),
scalaVersion := V.scala3,
crossScalaVersions := List(V.scala3),
organization := "org.scalameta",
licenses := Seq(
"Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")
Expand Down Expand Up @@ -138,7 +138,7 @@ commands ++= Seq(
runMtagsPublishLocal(st, v, localSnapshotVersion)
}
"interfaces/publishLocal" ::
s"++${V.scala213} metals/publishLocal" ::
s"++${V.scala3} metals/publishLocal" ::
"mtags-java/publishLocal" ::
publishMtags
},
Expand Down Expand Up @@ -226,6 +226,27 @@ val sharedSettings = sharedJavacOptions ++ sharedScalacOptions ++ List(
)
),
),
excludeDependencies ++= crossSetting(
scalaVersion.value,
if3 = {
// Exclude cross published version dependencies leading to conflicts in Scala 3 vs 2.13
// When using Scala 3 exclude Scala 2.13 standard native libraries,
// when using Scala 2.13 exclude Scala 3 standard native libraries
// Use full name, Maven style published artifacts cannot use artifact/cross version for exclusion rules
List(
ExclusionRule()
.withOrganization("org.scala-lang.modules")
.withName(
"scala-collection-compat_2.13"
),
ExclusionRule()
.withOrganization("org.scala-lang.modules")
.withName(
"scala-xml_2.13"
),
)
},
),
scalacOptions ++= lintingOptions(scalaVersion.value),
)

Expand Down Expand Up @@ -293,21 +314,19 @@ def multiScalaDirectories(root: File, scalaVersion: String) = {
result.toList
}

def scala3ScalametaDependency =
("org.scalameta" %% "scalameta" % V.scalameta)
.cross(CrossVersion.for3Use2_13)
.exclude("org.scala-lang", "scala-reflect")
.exclude("org.scala-lang", "scala-compiler")
// the correct one should be brought in by the scala 3 compiler
.exclude("org.scala-lang", "scala-library")
.exclude(
"com.lihaoyi",
"geny_2.13",
) // avoid 2.13 and 3 on the classpath since we rely on it directly
.exclude(
"com.lihaoyi",
"sourcecode_2.13",
) // avoid 2.13 and 3 on the classpath since it comes in via pprint
def scalametaDependency = ("org.scalameta" %% "scalameta" % V.scalameta)
.cross(CrossVersion.for3Use2_13)
.exclude("org.scala-lang", "scala-reflect")
.exclude("org.scala-lang", "scala-compiler")
.exclude("org.scala-lang.modules", "scala-collection-compat")
.exclude(
"com.lihaoyi",
"geny_2.13",
) // avoid 2.13 and 3 on the classpath since we rely on it directly
.exclude(
"com.lihaoyi",
"sourcecode_2.13",
)

val mtagsSettings = List(
crossScalaVersions := V.supportedScalaVersions ++ V.nightlyScala3Versions,
Expand Down Expand Up @@ -340,7 +359,7 @@ val mtagsSettings = List(
),
if3 = List(
"org.scala-lang" %% "scala3-compiler" % scalaVersion.value,
scala3ScalametaDependency,
scalametaDependency,
),
if3WithPresentationCompiler = List(
"org.scala-lang" %% "scala3-presentation-compiler" % scalaVersion.value
Expand Down Expand Up @@ -374,21 +393,21 @@ val mtagsSettings = List(
},
)

lazy val mtags3 = project
lazy val mtags2 = project
.in(file(".mtags"))
.settings(
Compile / unmanagedSourceDirectories := Seq(),
sharedSettings,
mtagsSettings,
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags" / "src" / "main" / "scala",
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala",
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala-3",
moduleName := "mtags3",
scalaVersion := V.scala3,
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target3",
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala-2.13",
moduleName := "mtags2",
scalaVersion := V.scala213,
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target2",
publish / skip := true,
scalafixConfig := Some(
(ThisBuild / baseDirectory).value / ".scalafix3.conf"
(ThisBuild / baseDirectory).value / ".scalafix2.conf"
),
)
.dependsOn(interfaces)
Expand All @@ -405,9 +424,6 @@ lazy val mtags3WithPresentationCompiler = project
scalaVersion := V.wrapperMetalsVersion,
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target3-wrapper",
publish / skip := true,
scalafixConfig := Some(
(ThisBuild / baseDirectory).value / ".scalafix3.conf"
),
)
.dependsOn(interfaces)
.enablePlugins(BuildInfoPlugin)
Expand Down Expand Up @@ -457,7 +473,8 @@ lazy val metals = project
// for BSP
"org.scala-sbt.ipcsocket" % "ipcsocket" % "1.6.2",
"ch.epfl.scala" % "bsp4j" % V.bsp,
"ch.epfl.scala" %% "bloop-launcher-core" % V.bloop,
("ch.epfl.scala" %% "bloop-launcher-core" % V.bloop)
.cross(CrossVersion.for3Use2_13),
// for LSP
V.lsp4j,
// for DAP
Expand Down Expand Up @@ -487,14 +504,20 @@ lazy val metals = project
// Scala dependencies
// ==================
"org.scalameta" % "mdoc-interfaces" % V.mdoc,
"org.scalameta" %% "scalafmt-dynamic" % V.scalafmt,
("org.scalameta" %% "scalafmt-dynamic" % V.scalafmt)
.cross(CrossVersion.for3Use2_13),
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0",
"ch.epfl.scala" % "scalafix-interfaces" % V.scalafix,
// For reading classpaths.
// for fetching ch.epfl.scala:bloop-frontend and other library dependencies
"io.get-coursier" % "interface" % V.coursierInterfaces,
// for comparing versions && fetching from sbt maven repository
"io.get-coursier" %% "coursier" % V.coursier,
"io.get-coursier" %% "coursier-sbt-maven-repository" % V.coursier,
// for comparing versions
("io.get-coursier" %% "versions" % "0.3.2")
.cross(CrossVersion.for3Use2_13),
("io.get-coursier" %% "coursier-sbt-maven-repository" % V.coursier)
.cross(CrossVersion.for3Use2_13),
("io.get-coursier" %% "coursier" % V.coursier)
.cross(CrossVersion.for3Use2_13),
// for logging
"com.outr" %% "scribe" % V.scribe,
"com.outr" %% "scribe-file" % V.scribe,
Expand All @@ -503,13 +526,12 @@ lazy val metals = project
"com.lihaoyi" %% "ujson" % "3.1.3",
// For remote language server
"com.lihaoyi" %% "requests" % "0.8.0",
// for producing SemanticDB from Scala source files, to be sure we want the same version of scalameta
"org.scalameta" %% "scalameta" % V.semanticdb(scalaVersion.value),
"org.scalameta" % "semanticdb-scalac-core" % V.semanticdb(
scalaVersion.value
) cross CrossVersion.full,
// for producing SemanticDB from Scala source files
scalametaDependency,
// "org.scalameta" % "semanticdb-scalac-core" % V.scalameta cross CrossVersion.full,
// For starting Ammonite
"io.github.alexarchambault.ammonite" %% "ammonite-runner" % "0.4.0",
("io.github.alexarchambault.ammonite" %% "ammonite-runner" % "0.4.0")
.cross(CrossVersion.for3Use2_13),
"org.scala-lang.modules" %% "scala-xml" % "2.2.0",
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4",
("org.virtuslab.scala-cli" % "scala-cli-bsp" % V.scalaCli)
Expand Down Expand Up @@ -577,6 +599,7 @@ lazy val `sbt-metals` = project
lazy val input = project
.in(file("tests/input"))
.settings(
scalaVersion := V.scala213,
sharedSettings,
publish / skip := true,
libraryDependencies ++= List(
Expand Down Expand Up @@ -710,7 +733,7 @@ lazy val mtest = project
),
libraryDependencies ++= {
if (isScala3WithPresentationCompiler(scalaVersion.value))
List(scala3ScalametaDependency)
List(scalametaDependency)
else Nil
},
Compile / unmanagedSourceDirectories ++= {
Expand Down Expand Up @@ -762,6 +785,7 @@ def isInTestShard(name: String, logger: Logger): Boolean = {
lazy val metalsDependencies = project
.in(file("target/.dependencies"))
.settings(
scalaVersion := V.scala213,
publish / skip := true,
// silent the intransitive dependency warning
publishMavenStyle := false,
Expand All @@ -770,13 +794,13 @@ lazy val metalsDependencies = project
// will pick them up and update them. They aren't actually used.
"com.lihaoyi" %% "ammonite-util" % V.ammonite,
"org.typelevel" % "kind-projector" % V.kindProjector cross CrossVersion.full,
"com.olegpy" %% "better-monadic-for" % V.betterMonadicFor,
("com.olegpy" %% "better-monadic-for" % V.betterMonadicFor),
"com.lihaoyi" % "mill-contrib-testng" % V.mill,
"org.virtuslab.scala-cli" % "cli_3" % V.scalaCli intransitive (),
"ch.epfl.scala" % "bloop-maven-plugin" % V.mavenBloop,
"ch.epfl.scala" %% "gradle-bloop" % V.gradleBloop,
"com.sourcegraph" % "semanticdb-java" % V.javaSemanticdb,
"ch.epfl.scala" %% "scala-debug-adapter" % V.debugAdapter intransitive (),
("ch.epfl.scala" %% "scala-debug-adapter" % V.debugAdapter) intransitive (),
),
)
.disablePlugins(ScalafixPlugin)
Expand All @@ -791,9 +815,16 @@ lazy val unit = project
sharedSettings,
Test / javaOptions += "-Xmx2G",
libraryDependencies ++= List(
"io.get-coursier" %% "coursier" % V.coursier, // for jars
"ch.epfl.scala" %% "bloop-config" % V.bloopConfig,
("io.get-coursier" %% "coursier" % V.coursier)
.cross(CrossVersion.for3Use2_13), // for jars
("ch.epfl.scala" %% "bloop-config" % V.bloopConfig)
.cross(CrossVersion.for3Use2_13),
"org.scalameta" %% "munit" % V.munit,
// The dependencies listed below are only listed so Scala Steward
// will pick them up and update them. They aren't actually used.
("com.lihaoyi" %% "ammonite-util" % V.ammonite intransitive ())
.cross(CrossVersion.for3Use2_13),
"com.lihaoyi" % "mill-contrib-testng" % V.mill intransitive (),
),
buildInfoPackage := "tests",
Compile / resourceGenerators += InputProperties
Expand Down
43 changes: 0 additions & 43 deletions metals-bench/src/main/scala/bench/MetalsBench.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
package bench

import scala.reflect.internal.util.BatchSourceFile
import scala.reflect.io.VirtualFile
import scala.tools.nsc.interactive.Global

import scala.meta.dialects
import scala.meta.interactive.InteractiveSemanticdb
import scala.meta.internal.metals.EmptyReportContext
import scala.meta.internal.metals.JdkSources
import scala.meta.internal.metals.ReportContext
Expand All @@ -19,7 +14,6 @@ import scala.meta.internal.mtags.SemanticdbClasspath
import scala.meta.internal.parsing.Trees
import scala.meta.internal.semanticdb.TextDocument
import scala.meta.internal.tokenizers.LegacyScanner
import scala.meta.internal.tokenizers.LegacyToken
import scala.meta.io.AbsolutePath
import scala.meta.io.Classpath

Expand Down Expand Up @@ -109,22 +103,6 @@ class MetalsBench {
}
}

@Benchmark
@BenchmarkMode(Array(Mode.SingleShotTime))
def scalacTokenize(): Unit = {
val g = global
scalaDependencySources.inputs.foreach { input =>
val unit = new g.CompilationUnit(
new BatchSourceFile(new VirtualFile(input.path), input.chars)
)
val scanner = g.newUnitScanner(unit)
scanner.init()
while (scanner.token != LegacyToken.EOF) {
scanner.nextToken()
}
}
}

@Benchmark
@BenchmarkMode(Array(Mode.SingleShotTime))
def scalametaParse(): Unit = {
Expand All @@ -134,27 +112,6 @@ class MetalsBench {
}
}

lazy val global: Global = InteractiveSemanticdb.newCompiler()

@Benchmark
@BenchmarkMode(Array(Mode.SingleShotTime))
def scalacParse(): Unit = {
val g = global
scalaDependencySources.inputs.foreach { input =>
val unit = new g.CompilationUnit(
new BatchSourceFile(new VirtualFile(input.path), input.chars)
)
val tree = g.newUnitParser(unit).parse()
var i = 0
new g.Traverser {
override def apply[T <: g.Tree](tree: T): T = {
i += 1
super.apply(tree)
}
}.traverse(tree)
}
}

@Benchmark
@BenchmarkMode(Array(Mode.SingleShotTime))
def mtagsJavaParse(): Unit = {
Expand Down
Loading

0 comments on commit 1f4dabb

Please sign in to comment.