Skip to content

Commit 61babdb

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 c5d6c7a commit 61babdb

File tree

220 files changed

+1092
-1048
lines changed

Some content is hidden

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

220 files changed

+1092
-1048
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
@@ -44,16 +44,16 @@ def crossSetting[A](
4444
logo := Welcome.logo
4545
usefulTasks := Welcome.tasks
4646

47-
ThisBuild / scalafixScalaBinaryVersion := scalaBinaryVersion.value
47+
ThisBuild / scalafixScalaBinaryVersion := "2.13"
4848

4949
inThisBuild(
5050
List(
5151
version ~= { dynVer =>
5252
if (isCI) dynVer
5353
else localSnapshotVersion // only for local publishing
5454
},
55-
scalaVersion := V.scala213,
56-
crossScalaVersions := List(V.scala213),
55+
scalaVersion := V.scala3,
56+
crossScalaVersions := List(V.scala3),
5757
organization := "org.scalameta",
5858
licenses := Seq(
5959
"Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")
@@ -136,7 +136,7 @@ commands ++= Seq(
136136
runMtagsPublishLocal(st, v, localSnapshotVersion)
137137
}
138138
"interfaces/publishLocal" ::
139-
s"++${V.scala213} metals/publishLocal" ::
139+
s"++${V.scala3} metals/publishLocal" ::
140140
"mtags-java/publishLocal" ::
141141
publishMtags
142142
},
@@ -224,6 +224,27 @@ val sharedSettings = sharedJavacOptions ++ sharedScalacOptions ++ List(
224224
)
225225
),
226226
),
227+
excludeDependencies ++= crossSetting(
228+
scalaVersion.value,
229+
if3 = {
230+
// Exclude cross published version dependencies leading to conflicts in Scala 3 vs 2.13
231+
// When using Scala 3 exclude Scala 2.13 standard native libraries,
232+
// when using Scala 2.13 exclude Scala 3 standard native libraries
233+
// Use full name, Maven style published artifacts cannot use artifact/cross version for exclusion rules
234+
List(
235+
ExclusionRule()
236+
.withOrganization("org.scala-lang.modules")
237+
.withName(
238+
"scala-collection-compat_2.13"
239+
),
240+
ExclusionRule()
241+
.withOrganization("org.scala-lang.modules")
242+
.withName(
243+
"scala-xml_2.13"
244+
),
245+
)
246+
},
247+
),
227248
scalacOptions ++= lintingOptions(scalaVersion.value),
228249
)
229250

@@ -291,21 +312,19 @@ def multiScalaDirectories(root: File, scalaVersion: String) = {
291312
result.toList
292313
}
293314

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

310329
val mtagsSettings = List(
311330
crossScalaVersions := V.supportedScalaVersions ++ V.nightlyScala3Versions,
@@ -338,7 +357,7 @@ val mtagsSettings = List(
338357
),
339358
if3 = List(
340359
"org.scala-lang" %% "scala3-compiler" % scalaVersion.value,
341-
scala3ScalametaDependency,
360+
scalametaDependency,
342361
),
343362
if3WithPresentationCompiler = List(
344363
"org.scala-lang" %% "scala3-presentation-compiler" % scalaVersion.value
@@ -372,21 +391,21 @@ val mtagsSettings = List(
372391
},
373392
)
374393

375-
lazy val mtags3 = project
394+
lazy val mtags2 = project
376395
.in(file(".mtags"))
377396
.settings(
378397
Compile / unmanagedSourceDirectories := Seq(),
379398
sharedSettings,
380399
mtagsSettings,
381400
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags" / "src" / "main" / "scala",
382401
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala",
383-
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala-3",
384-
moduleName := "mtags3",
385-
scalaVersion := V.scala3,
386-
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target3",
402+
Compile / unmanagedSourceDirectories += (ThisBuild / baseDirectory).value / "mtags-shared" / "src" / "main" / "scala-2.13",
403+
moduleName := "mtags2",
404+
scalaVersion := V.scala213,
405+
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target2",
387406
publish / skip := true,
388407
scalafixConfig := Some(
389-
(ThisBuild / baseDirectory).value / ".scalafix3.conf"
408+
(ThisBuild / baseDirectory).value / ".scalafix2.conf"
390409
),
391410
)
392411
.dependsOn(interfaces)
@@ -403,9 +422,6 @@ lazy val mtags3WithPresentationCompiler = project
403422
scalaVersion := V.wrapperMetalsVersion,
404423
target := (ThisBuild / baseDirectory).value / "mtags" / "target" / "target3-wrapper",
405424
publish / skip := true,
406-
scalafixConfig := Some(
407-
(ThisBuild / baseDirectory).value / ".scalafix3.conf"
408-
),
409425
)
410426
.dependsOn(interfaces)
411427
.enablePlugins(BuildInfoPlugin)
@@ -455,7 +471,8 @@ lazy val metals = project
455471
// for BSP
456472
"org.scala-sbt.ipcsocket" % "ipcsocket" % "1.6.2",
457473
"ch.epfl.scala" % "bsp4j" % V.bsp,
458-
"ch.epfl.scala" %% "bloop-launcher-core" % V.bloop,
474+
("ch.epfl.scala" %% "bloop-launcher-core" % V.bloop)
475+
.cross(CrossVersion.for3Use2_13),
459476
// for LSP
460477
V.lsp4j,
461478
// for DAP
@@ -485,14 +502,20 @@ lazy val metals = project
485502
// Scala dependencies
486503
// ==================
487504
"org.scalameta" % "mdoc-interfaces" % V.mdoc,
488-
"org.scalameta" %% "scalafmt-dynamic" % V.scalafmt,
505+
("org.scalameta" %% "scalafmt-dynamic" % V.scalafmt)
506+
.cross(CrossVersion.for3Use2_13),
507+
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0",
489508
"ch.epfl.scala" % "scalafix-interfaces" % V.scalafix,
490509
// For reading classpaths.
491510
// for fetching ch.epfl.scala:bloop-frontend and other library dependencies
492511
"io.get-coursier" % "interface" % V.coursierInterfaces,
493-
// for comparing versions && fetching from sbt maven repository
494-
"io.get-coursier" %% "coursier" % V.coursier,
495-
"io.get-coursier" %% "coursier-sbt-maven-repository" % V.coursier,
512+
// for comparing versions
513+
("io.get-coursier" %% "versions" % "0.3.2")
514+
.cross(CrossVersion.for3Use2_13),
515+
("io.get-coursier" %% "coursier-sbt-maven-repository" % V.coursier)
516+
.cross(CrossVersion.for3Use2_13),
517+
("io.get-coursier" %% "coursier" % V.coursier)
518+
.cross(CrossVersion.for3Use2_13),
496519
// for logging
497520
"com.outr" %% "scribe" % V.scribe,
498521
"com.outr" %% "scribe-file" % V.scribe,
@@ -501,13 +524,12 @@ lazy val metals = project
501524
"com.lihaoyi" %% "ujson" % "3.1.3",
502525
// For remote language server
503526
"com.lihaoyi" %% "requests" % "0.8.0",
504-
// for producing SemanticDB from Scala source files, to be sure we want the same version of scalameta
505-
"org.scalameta" %% "scalameta" % V.semanticdb(scalaVersion.value),
506-
"org.scalameta" % "semanticdb-scalac-core" % V.semanticdb(
507-
scalaVersion.value
508-
) cross CrossVersion.full,
527+
// for producing SemanticDB from Scala source files
528+
scalametaDependency,
529+
// "org.scalameta" % "semanticdb-scalac-core" % V.scalameta cross CrossVersion.full,
509530
// For starting Ammonite
510-
"io.github.alexarchambault.ammonite" %% "ammonite-runner" % "0.4.0",
531+
("io.github.alexarchambault.ammonite" %% "ammonite-runner" % "0.4.0")
532+
.cross(CrossVersion.for3Use2_13),
511533
"org.scala-lang.modules" %% "scala-xml" % "2.2.0",
512534
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4",
513535
("org.virtuslab.scala-cli" % "scala-cli-bsp" % V.scalaCli)
@@ -575,6 +597,7 @@ lazy val `sbt-metals` = project
575597
lazy val input = project
576598
.in(file("tests/input"))
577599
.settings(
600+
scalaVersion := V.scala213,
578601
sharedSettings,
579602
publish / skip := true,
580603
libraryDependencies ++= List(
@@ -708,7 +731,7 @@ lazy val mtest = project
708731
),
709732
libraryDependencies ++= {
710733
if (isScala3WithPresentationCompiler(scalaVersion.value))
711-
List(scala3ScalametaDependency)
734+
List(scalametaDependency)
712735
else Nil
713736
},
714737
Compile / unmanagedSourceDirectories ++= {
@@ -760,6 +783,7 @@ def isInTestShard(name: String, logger: Logger): Boolean = {
760783
lazy val metalsDependencies = project
761784
.in(file("target/.dependencies"))
762785
.settings(
786+
scalaVersion := V.scala213,
763787
publish / skip := true,
764788
// silent the intransitive dependency warning
765789
publishMavenStyle := false,
@@ -768,13 +792,13 @@ lazy val metalsDependencies = project
768792
// will pick them up and update them. They aren't actually used.
769793
"com.lihaoyi" %% "ammonite-util" % V.ammonite,
770794
"org.typelevel" % "kind-projector" % V.kindProjector cross CrossVersion.full,
771-
"com.olegpy" %% "better-monadic-for" % V.betterMonadicFor,
795+
("com.olegpy" %% "better-monadic-for" % V.betterMonadicFor),
772796
"com.lihaoyi" % "mill-contrib-testng" % V.mill,
773797
"org.virtuslab.scala-cli" % "cli_3" % V.scalaCli intransitive (),
774798
"ch.epfl.scala" % "bloop-maven-plugin" % V.mavenBloop,
775799
"ch.epfl.scala" %% "gradle-bloop" % V.gradleBloop,
776800
"com.sourcegraph" % "semanticdb-java" % V.javaSemanticdb,
777-
"ch.epfl.scala" %% "scala-debug-adapter" % V.debugAdapter intransitive (),
801+
("ch.epfl.scala" %% "scala-debug-adapter" % V.debugAdapter) intransitive (),
778802
),
779803
)
780804
.disablePlugins(ScalafixPlugin)
@@ -789,9 +813,16 @@ lazy val unit = project
789813
sharedSettings,
790814
Test / javaOptions += "-Xmx2G",
791815
libraryDependencies ++= List(
792-
"io.get-coursier" %% "coursier" % V.coursier, // for jars
793-
"ch.epfl.scala" %% "bloop-config" % V.bloopConfig,
816+
("io.get-coursier" %% "coursier" % V.coursier)
817+
.cross(CrossVersion.for3Use2_13), // for jars
818+
("ch.epfl.scala" %% "bloop-config" % V.bloopConfig)
819+
.cross(CrossVersion.for3Use2_13),
794820
"org.scalameta" %% "munit" % V.munit,
821+
// The dependencies listed below are only listed so Scala Steward
822+
// will pick them up and update them. They aren't actually used.
823+
("com.lihaoyi" %% "ammonite-util" % V.ammonite intransitive ())
824+
.cross(CrossVersion.for3Use2_13),
825+
"com.lihaoyi" % "mill-contrib-testng" % V.mill intransitive (),
795826
),
796827
buildInfoPackage := "tests",
797828
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)