Skip to content

Commit 1f4dabb

Browse files
committed
refactor: Migrate Metals server to Scala 3
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)
1 parent d596f64 commit 1f4dabb

File tree

221 files changed

+1098
-1054
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

221 files changed

+1098
-1054
lines changed

.scalafix.conf

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
rules = [
2-
OrganizeImports,
3-
ExplicitResultTypes,
4-
RemoveUnused
2+
OrganizeImports
53
]
64

7-
ExplicitResultTypes.rewriteStructuralTypesToNamedSubclass = false
8-
9-
RemoveUnused.imports = false
10-
115
OrganizeImports.groupedImports = Explode
126
OrganizeImports.expandRelative = true
13-
OrganizeImports.removeUnused = true
7+
OrganizeImports.removeUnused = false
148
OrganizeImports.groups = [
159
"re:javax?\\."
1610
"scala."

.scalafix2.conf

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
rules = [
2+
OrganizeImports,
3+
ExplicitResultTypes,
4+
RemoveUnused
5+
]
6+
7+
ExplicitResultTypes.rewriteStructuralTypesToNamedSubclass = false
8+
9+
RemoveUnused.imports = false
10+
11+
OrganizeImports.groupedImports = Explode
12+
OrganizeImports.expandRelative = true
13+
OrganizeImports.removeUnused = true
14+
OrganizeImports.groups = [
15+
"re:javax?\\."
16+
"scala."
17+
"scala.meta."
18+
"*"
19+
]

.scalafix3.conf

-13
This file was deleted.

.scalafmt.conf

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
version = "3.7.17"
2-
runner.dialect = scala213
2+
runner.dialect = scala3
33
project.git = true
44
align.preset = none
55
align.stripMargin = true
@@ -34,6 +34,7 @@ fileOverride {
3434
},
3535
"glob:**/mtags*/**" {
3636
trailingCommas = never
37+
runner.dialect = scala213
3738
}
3839
"glob:**/tests/cross/src/**" {
3940
trailingCommas = never

build.sbt

+76-45
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ def crossSetting[A](
4646
logo := Welcome.logo
4747
usefulTasks := Welcome.tasks
4848

49-
ThisBuild / scalafixScalaBinaryVersion := scalaBinaryVersion.value
49+
ThisBuild / scalafixScalaBinaryVersion := "2.13"
5050

5151
inThisBuild(
5252
List(
5353
version ~= { dynVer =>
5454
if (isCI) dynVer
5555
else localSnapshotVersion // only for local publishing
5656
},
57-
scalaVersion := V.scala213,
58-
crossScalaVersions := List(V.scala213),
57+
scalaVersion := V.scala3,
58+
crossScalaVersions := List(V.scala3),
5959
organization := "org.scalameta",
6060
licenses := Seq(
6161
"Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")
@@ -138,7 +138,7 @@ commands ++= Seq(
138138
runMtagsPublishLocal(st, v, localSnapshotVersion)
139139
}
140140
"interfaces/publishLocal" ::
141-
s"++${V.scala213} metals/publishLocal" ::
141+
s"++${V.scala3} metals/publishLocal" ::
142142
"mtags-java/publishLocal" ::
143143
publishMtags
144144
},
@@ -226,6 +226,27 @@ val sharedSettings = sharedJavacOptions ++ sharedScalacOptions ++ List(
226226
)
227227
),
228228
),
229+
excludeDependencies ++= crossSetting(
230+
scalaVersion.value,
231+
if3 = {
232+
// Exclude cross published version dependencies leading to conflicts in Scala 3 vs 2.13
233+
// When using Scala 3 exclude Scala 2.13 standard native libraries,
234+
// when using Scala 2.13 exclude Scala 3 standard native libraries
235+
// Use full name, Maven style published artifacts cannot use artifact/cross version for exclusion rules
236+
List(
237+
ExclusionRule()
238+
.withOrganization("org.scala-lang.modules")
239+
.withName(
240+
"scala-collection-compat_2.13"
241+
),
242+
ExclusionRule()
243+
.withOrganization("org.scala-lang.modules")
244+
.withName(
245+
"scala-xml_2.13"
246+
),
247+
)
248+
},
249+
),
229250
scalacOptions ++= lintingOptions(scalaVersion.value),
230251
)
231252

@@ -293,21 +314,19 @@ def multiScalaDirectories(root: File, scalaVersion: String) = {
293314
result.toList
294315
}
295316

296-
def scala3ScalametaDependency =
297-
("org.scalameta" %% "scalameta" % V.scalameta)
298-
.cross(CrossVersion.for3Use2_13)
299-
.exclude("org.scala-lang", "scala-reflect")
300-
.exclude("org.scala-lang", "scala-compiler")
301-
// the correct one should be brought in by the scala 3 compiler
302-
.exclude("org.scala-lang", "scala-library")
303-
.exclude(
304-
"com.lihaoyi",
305-
"geny_2.13",
306-
) // avoid 2.13 and 3 on the classpath since we rely on it directly
307-
.exclude(
308-
"com.lihaoyi",
309-
"sourcecode_2.13",
310-
) // avoid 2.13 and 3 on the classpath since it comes in via pprint
317+
def scalametaDependency = ("org.scalameta" %% "scalameta" % V.scalameta)
318+
.cross(CrossVersion.for3Use2_13)
319+
.exclude("org.scala-lang", "scala-reflect")
320+
.exclude("org.scala-lang", "scala-compiler")
321+
.exclude("org.scala-lang.modules", "scala-collection-compat")
322+
.exclude(
323+
"com.lihaoyi",
324+
"geny_2.13",
325+
) // avoid 2.13 and 3 on the classpath since we rely on it directly
326+
.exclude(
327+
"com.lihaoyi",
328+
"sourcecode_2.13",
329+
)
311330

312331
val mtagsSettings = List(
313332
crossScalaVersions := V.supportedScalaVersions ++ V.nightlyScala3Versions,
@@ -340,7 +359,7 @@ val mtagsSettings = List(
340359
),
341360
if3 = List(
342361
"org.scala-lang" %% "scala3-compiler" % scalaVersion.value,
343-
scala3ScalametaDependency,
362+
scalametaDependency,
344363
),
345364
if3WithPresentationCompiler = List(
346365
"org.scala-lang" %% "scala3-presentation-compiler" % scalaVersion.value
@@ -374,21 +393,21 @@ val mtagsSettings = List(
374393
},
375394
)
376395

377-
lazy val mtags3 = project
396+
lazy val mtags2 = project
378397
.in(file(".mtags"))
379398
.settings(
380399
Compile / unmanagedSourceDirectories := Seq(),
381400
sharedSettings,
382401
mtagsSettings,
383402
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags" / "src" / "main" / "scala",
384403
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala",
385-
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala-3",
386-
moduleName := "mtags3",
387-
scalaVersion := V.scala3,
388-
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target3",
404+
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala-2.13",
405+
moduleName := "mtags2",
406+
scalaVersion := V.scala213,
407+
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target2",
389408
publish / skip := true,
390409
scalafixConfig := Some(
391-
(ThisBuild / baseDirectory).value / ".scalafix3.conf"
410+
(ThisBuild / baseDirectory).value / ".scalafix2.conf"
392411
),
393412
)
394413
.dependsOn(interfaces)
@@ -405,9 +424,6 @@ lazy val mtags3WithPresentationCompiler = project
405424
scalaVersion := V.wrapperMetalsVersion,
406425
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target3-wrapper",
407426
publish / skip := true,
408-
scalafixConfig := Some(
409-
(ThisBuild / baseDirectory).value / ".scalafix3.conf"
410-
),
411427
)
412428
.dependsOn(interfaces)
413429
.enablePlugins(BuildInfoPlugin)
@@ -457,7 +473,8 @@ lazy val metals = project
457473
// for BSP
458474
"org.scala-sbt.ipcsocket" % "ipcsocket" % "1.6.2",
459475
"ch.epfl.scala" % "bsp4j" % V.bsp,
460-
"ch.epfl.scala" %% "bloop-launcher-core" % V.bloop,
476+
("ch.epfl.scala" %% "bloop-launcher-core" % V.bloop)
477+
.cross(CrossVersion.for3Use2_13),
461478
// for LSP
462479
V.lsp4j,
463480
// for DAP
@@ -487,14 +504,20 @@ lazy val metals = project
487504
// Scala dependencies
488505
// ==================
489506
"org.scalameta" % "mdoc-interfaces" % V.mdoc,
490-
"org.scalameta" %% "scalafmt-dynamic" % V.scalafmt,
507+
("org.scalameta" %% "scalafmt-dynamic" % V.scalafmt)
508+
.cross(CrossVersion.for3Use2_13),
509+
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0",
491510
"ch.epfl.scala" % "scalafix-interfaces" % V.scalafix,
492511
// For reading classpaths.
493512
// for fetching ch.epfl.scala:bloop-frontend and other library dependencies
494513
"io.get-coursier" % "interface" % V.coursierInterfaces,
495-
// for comparing versions && fetching from sbt maven repository
496-
"io.get-coursier" %% "coursier" % V.coursier,
497-
"io.get-coursier" %% "coursier-sbt-maven-repository" % V.coursier,
514+
// for comparing versions
515+
("io.get-coursier" %% "versions" % "0.3.2")
516+
.cross(CrossVersion.for3Use2_13),
517+
("io.get-coursier" %% "coursier-sbt-maven-repository" % V.coursier)
518+
.cross(CrossVersion.for3Use2_13),
519+
("io.get-coursier" %% "coursier" % V.coursier)
520+
.cross(CrossVersion.for3Use2_13),
498521
// for logging
499522
"com.outr" %% "scribe" % V.scribe,
500523
"com.outr" %% "scribe-file" % V.scribe,
@@ -503,13 +526,12 @@ lazy val metals = project
503526
"com.lihaoyi" %% "ujson" % "3.1.3",
504527
// For remote language server
505528
"com.lihaoyi" %% "requests" % "0.8.0",
506-
// for producing SemanticDB from Scala source files, to be sure we want the same version of scalameta
507-
"org.scalameta" %% "scalameta" % V.semanticdb(scalaVersion.value),
508-
"org.scalameta" % "semanticdb-scalac-core" % V.semanticdb(
509-
scalaVersion.value
510-
) cross CrossVersion.full,
529+
// for producing SemanticDB from Scala source files
530+
scalametaDependency,
531+
// "org.scalameta" % "semanticdb-scalac-core" % V.scalameta cross CrossVersion.full,
511532
// For starting Ammonite
512-
"io.github.alexarchambault.ammonite" %% "ammonite-runner" % "0.4.0",
533+
("io.github.alexarchambault.ammonite" %% "ammonite-runner" % "0.4.0")
534+
.cross(CrossVersion.for3Use2_13),
513535
"org.scala-lang.modules" %% "scala-xml" % "2.2.0",
514536
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4",
515537
("org.virtuslab.scala-cli" % "scala-cli-bsp" % V.scalaCli)
@@ -577,6 +599,7 @@ lazy val `sbt-metals` = project
577599
lazy val input = project
578600
.in(file("tests/input"))
579601
.settings(
602+
scalaVersion := V.scala213,
580603
sharedSettings,
581604
publish / skip := true,
582605
libraryDependencies ++= List(
@@ -710,7 +733,7 @@ lazy val mtest = project
710733
),
711734
libraryDependencies ++= {
712735
if (isScala3WithPresentationCompiler(scalaVersion.value))
713-
List(scala3ScalametaDependency)
736+
List(scalametaDependency)
714737
else Nil
715738
},
716739
Compile / unmanagedSourceDirectories ++= {
@@ -762,6 +785,7 @@ def isInTestShard(name: String, logger: Logger): Boolean = {
762785
lazy val metalsDependencies = project
763786
.in(file("target/.dependencies"))
764787
.settings(
788+
scalaVersion := V.scala213,
765789
publish / skip := true,
766790
// silent the intransitive dependency warning
767791
publishMavenStyle := false,
@@ -770,13 +794,13 @@ lazy val metalsDependencies = project
770794
// will pick them up and update them. They aren't actually used.
771795
"com.lihaoyi" %% "ammonite-util" % V.ammonite,
772796
"org.typelevel" % "kind-projector" % V.kindProjector cross CrossVersion.full,
773-
"com.olegpy" %% "better-monadic-for" % V.betterMonadicFor,
797+
("com.olegpy" %% "better-monadic-for" % V.betterMonadicFor),
774798
"com.lihaoyi" % "mill-contrib-testng" % V.mill,
775799
"org.virtuslab.scala-cli" % "cli_3" % V.scalaCli intransitive (),
776800
"ch.epfl.scala" % "bloop-maven-plugin" % V.mavenBloop,
777801
"ch.epfl.scala" %% "gradle-bloop" % V.gradleBloop,
778802
"com.sourcegraph" % "semanticdb-java" % V.javaSemanticdb,
779-
"ch.epfl.scala" %% "scala-debug-adapter" % V.debugAdapter intransitive (),
803+
("ch.epfl.scala" %% "scala-debug-adapter" % V.debugAdapter) intransitive (),
780804
),
781805
)
782806
.disablePlugins(ScalafixPlugin)
@@ -791,9 +815,16 @@ lazy val unit = project
791815
sharedSettings,
792816
Test / javaOptions += "-Xmx2G",
793817
libraryDependencies ++= List(
794-
"io.get-coursier" %% "coursier" % V.coursier, // for jars
795-
"ch.epfl.scala" %% "bloop-config" % V.bloopConfig,
818+
("io.get-coursier" %% "coursier" % V.coursier)
819+
.cross(CrossVersion.for3Use2_13), // for jars
820+
("ch.epfl.scala" %% "bloop-config" % V.bloopConfig)
821+
.cross(CrossVersion.for3Use2_13),
796822
"org.scalameta" %% "munit" % V.munit,
823+
// The dependencies listed below are only listed so Scala Steward
824+
// will pick them up and update them. They aren't actually used.
825+
("com.lihaoyi" %% "ammonite-util" % V.ammonite intransitive ())
826+
.cross(CrossVersion.for3Use2_13),
827+
"com.lihaoyi" % "mill-contrib-testng" % V.mill intransitive (),
797828
),
798829
buildInfoPackage := "tests",
799830
Compile / resourceGenerators += InputProperties

metals-bench/src/main/scala/bench/MetalsBench.scala

-43
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
package bench
22

3-
import scala.reflect.internal.util.BatchSourceFile
4-
import scala.reflect.io.VirtualFile
5-
import scala.tools.nsc.interactive.Global
6-
73
import scala.meta.dialects
8-
import scala.meta.interactive.InteractiveSemanticdb
94
import scala.meta.internal.metals.EmptyReportContext
105
import scala.meta.internal.metals.JdkSources
116
import scala.meta.internal.metals.ReportContext
@@ -19,7 +14,6 @@ import scala.meta.internal.mtags.SemanticdbClasspath
1914
import scala.meta.internal.parsing.Trees
2015
import scala.meta.internal.semanticdb.TextDocument
2116
import scala.meta.internal.tokenizers.LegacyScanner
22-
import scala.meta.internal.tokenizers.LegacyToken
2317
import scala.meta.io.AbsolutePath
2418
import scala.meta.io.Classpath
2519

@@ -109,22 +103,6 @@ class MetalsBench {
109103
}
110104
}
111105

112-
@Benchmark
113-
@BenchmarkMode(Array(Mode.SingleShotTime))
114-
def scalacTokenize(): Unit = {
115-
val g = global
116-
scalaDependencySources.inputs.foreach { input =>
117-
val unit = new g.CompilationUnit(
118-
new BatchSourceFile(new VirtualFile(input.path), input.chars)
119-
)
120-
val scanner = g.newUnitScanner(unit)
121-
scanner.init()
122-
while (scanner.token != LegacyToken.EOF) {
123-
scanner.nextToken()
124-
}
125-
}
126-
}
127-
128106
@Benchmark
129107
@BenchmarkMode(Array(Mode.SingleShotTime))
130108
def scalametaParse(): Unit = {
@@ -134,27 +112,6 @@ class MetalsBench {
134112
}
135113
}
136114

137-
lazy val global: Global = InteractiveSemanticdb.newCompiler()
138-
139-
@Benchmark
140-
@BenchmarkMode(Array(Mode.SingleShotTime))
141-
def scalacParse(): Unit = {
142-
val g = global
143-
scalaDependencySources.inputs.foreach { input =>
144-
val unit = new g.CompilationUnit(
145-
new BatchSourceFile(new VirtualFile(input.path), input.chars)
146-
)
147-
val tree = g.newUnitParser(unit).parse()
148-
var i = 0
149-
new g.Traverser {
150-
override def apply[T <: g.Tree](tree: T): T = {
151-
i += 1
152-
super.apply(tree)
153-
}
154-
}.traverse(tree)
155-
}
156-
}
157-
158115
@Benchmark
159116
@BenchmarkMode(Array(Mode.SingleShotTime))
160117
def mtagsJavaParse(): Unit = {

0 commit comments

Comments
 (0)