From 1dfec99d7a0b6299a4c639b99d4c097872b03c9f Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 02:34:56 +0200 Subject: [PATCH 01/13] . --- .../src/mill/bsp/worker/MillBuildServer.scala | 2 +- bsp/worker/src/mill/bsp/worker/Utils.scala | 2 +- .../mill/contrib/buildinfo/BuildInfo.scala | 2 +- .../src/mill/playlib/RouterModule.scala | 3 +- .../playlib/src/mill/playlib/Version.scala | 4 +- .../src/mill/playlib/PlayModuleTests.scala | 3 +- .../src/mill/playlib/RouterModuleTests.scala | 4 +- .../api/ScoverageReportWorkerApi.scala | 46 --------- .../api/ScoverageReportWorkerApi2.java | 95 +++++++++++++++++++ .../contrib/scoverage/ScoverageModule.scala | 2 +- .../contrib/scoverage/ScoverageReport.scala | 2 +- .../scoverage/ScoverageReportWorker.scala | 65 +++++++++++-- .../worker/ScoverageReportWorkerImpl.scala | 32 ++++--- .../src/mill/twirllib/TwirlModule.scala | 4 +- .../src/mill/twirllib/HelloWorldTests.scala | 13 ++- example/thirdparty/mockito/build.mill | 14 +++ example/thirdparty/netty/build.mill | 4 +- .../mill-build/mill-build/build.mill | 2 +- .../src/MultiLevelBuildTests.scala | 44 ++++----- 19 files changed, 233 insertions(+), 110 deletions(-) delete mode 100644 contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi.scala create mode 100644 contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi2.java diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index 727be75c932c..23ec8ca7d398 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -632,7 +632,7 @@ private class MillBuildServer( State ) => V): CompletableFuture[V] = { val prefix = hint.split(" ").head - completable(hint) { state: State => + completable(hint) { (state: State) => val ids = state.filterNonSynthetic(targetIds(state).asJava).asScala val tasksSeq = ids.flatMap { id => val (m, ev) = state.bspModulesById(id) diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index 5fe3f57b1900..7b96c76a88ea 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -34,7 +34,7 @@ private object Utils { originId: String, bspIdsByModule: Map[BspModule, BuildTargetIdentifier], client: BuildClient - ): Int => Option[CompileProblemReporter] = { moduleHashCode: Int => + ): Int => Option[CompileProblemReporter] = { (moduleHashCode: Int) => bspIdsByModule.find(_._1.hashCode == moduleHashCode).map { case (module: JavaModule, targetId) => val buildTarget = module.bspBuildTarget diff --git a/contrib/buildinfo/src/mill/contrib/buildinfo/BuildInfo.scala b/contrib/buildinfo/src/mill/contrib/buildinfo/BuildInfo.scala index 2f83bc600503..dcd6f0d8bcee 100644 --- a/contrib/buildinfo/src/mill/contrib/buildinfo/BuildInfo.scala +++ b/contrib/buildinfo/src/mill/contrib/buildinfo/BuildInfo.scala @@ -173,7 +173,7 @@ object BuildInfo { |package ${buildInfoPackageName} | |object $buildInfoObjectName { - | private[this] val buildInfoProperties: java.util.Properties = new java.util.Properties() + | private val buildInfoProperties: java.util.Properties = new java.util.Properties() | | { | val buildInfoInputStream = getClass diff --git a/contrib/playlib/src/mill/playlib/RouterModule.scala b/contrib/playlib/src/mill/playlib/RouterModule.scala index fdfeaa2605f4..67123db1df07 100644 --- a/contrib/playlib/src/mill/playlib/RouterModule.scala +++ b/contrib/playlib/src/mill/playlib/RouterModule.scala @@ -80,7 +80,8 @@ trait RouterModule extends ScalaModule with Version { repositoriesTask(), artifactSuffix = playMinorVersion() match { case "2.6" => "_2.12" - case _ => "_2.13" + case "2.7" | "2.8" => "_2.13" + case _ => "_3" } ) } diff --git a/contrib/playlib/src/mill/playlib/Version.scala b/contrib/playlib/src/mill/playlib/Version.scala index c129d3820cf4..a9640fac8eea 100644 --- a/contrib/playlib/src/mill/playlib/Version.scala +++ b/contrib/playlib/src/mill/playlib/Version.scala @@ -12,11 +12,11 @@ private[playlib] trait Version extends Module { playVersion().split('.').take(2).mkString(".") } - private[playlib] def playOrganization: T[String] = Task.Anon { + private[playlib] def playOrganization: Task[String] = Task.Anon { if (playVersion().startsWith("2.")) "com.typesafe.play" else "org.playframework" } - private[playlib] def component(id: String) = Task.Anon { + private[playlib] def component(id: String): Task[Dep] = Task.Anon { ivy"${playOrganization()}::$id::${playVersion()}" } } diff --git a/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala b/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala index afd219fcd7c6..a6a97db4d6fc 100644 --- a/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala +++ b/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala @@ -1,6 +1,7 @@ package mill package playlib +import mill.scalalib.api.ZincWorkerUtil import mill.testkit.{TestBaseModule, UnitTester} import utest.{TestSuite, Tests, assert, _} @@ -102,7 +103,7 @@ object PlayModuleTests extends TestSuite with PlayTestSuite { os.RelPath("controllers/routes$javascript.class"), os.RelPath("controllers/javascript/ReverseHomeController.class"), os.RelPath("controllers/javascript/ReverseAssets.class"), - if (scalaVersion.startsWith("3.")) os.RelPath("router/Routes$$anon$1.class") + if (ZincWorkerUtil.isScala3(scalaVersion)) os.RelPath("router/Routes$$anon$1.class") else os.RelPath("router/Routes$$anonfun$routes$1.class"), os.RelPath("router/Routes.class"), os.RelPath("router/RoutesPrefix$.class"), diff --git a/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala b/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala index 718ddf27670e..c50199b2f862 100644 --- a/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala +++ b/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala @@ -71,7 +71,7 @@ object RouterModuleTests extends TestSuite with PlayTestSuite { val eitherResult = eval.apply(project.compileRouter) val Left(Failure(message, x)) = eitherResult val playExpectedMessage = - if (playVersion.startsWith("2.6.")) { + if (!playVersion.startsWith("2.7.") && !playVersion.startsWith("2.8.")) { "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" } else { "end of input expected" @@ -98,7 +98,7 @@ object RouterModuleTests extends TestSuite with PlayTestSuite { val eitherResult = eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) val Left(Failure(message, x)) = eitherResult val playExpectedMessage = - if (playVersion.startsWith("2.6.")) { + if (!playVersion.startsWith("2.7.") && !playVersion.startsWith("2.8.")) { "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" } else { "end of input expected" diff --git a/contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi.scala b/contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi.scala deleted file mode 100644 index 55fc01d3dc78..000000000000 --- a/contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi.scala +++ /dev/null @@ -1,46 +0,0 @@ -package mill.contrib.scoverage.api - -import mill.api.Ctx - -trait ScoverageReportWorkerApi { - import ScoverageReportWorkerApi._ - - @deprecated("Use other overload instead.", "Mill after 0.10.7") - def report( - reportType: ReportType, - sources: Seq[os.Path], - dataDirs: Seq[os.Path] - )(implicit - ctx: Ctx - ): Unit = { - report(reportType, sources, dataDirs, ctx.workspace) - } - - def report( - reportType: ReportType, - sources: Seq[os.Path], - dataDirs: Seq[os.Path], - sourceRoot: os.Path - )(implicit - ctx: Ctx - ): Unit = { - // FIXME: We only call the deprecated version here, to preserve binary compatibility. Remove when appropriate. - ctx.log.error( - "Binary compatibility stub may cause infinite loops with StackOverflowError. You need to implement: def report(ReportType, Seq[Path], Seq[Path], os.Path): Unit" - ) - report(reportType, sources, dataDirs) - } -} - -object ScoverageReportWorkerApi { - sealed trait ReportType - sealed trait FileReportType extends ReportType { def folderName: String } - object ReportType { - final case object Html extends FileReportType { val folderName: String = "htmlReport" } - final case object Xml extends FileReportType { val folderName: String = "xmlReport" } - final case object XmlCobertura extends FileReportType { - val folderName: String = "xmlCoberturaReport" - } - final case object Console extends ReportType - } -} diff --git a/contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi2.java b/contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi2.java new file mode 100644 index 000000000000..09868af8b3e1 --- /dev/null +++ b/contrib/scoverage/api/src/mill/contrib/scoverage/api/ScoverageReportWorkerApi2.java @@ -0,0 +1,95 @@ +package mill.contrib.scoverage.api; + +import java.nio.file.Path; +import java.nio.file.Files; +import java.io.IOException; +import java.io.Serializable; + +public interface ScoverageReportWorkerApi2 { + + interface Logger { + void info(String msg); + void error(String msg); + void debug(String msg); + } + + interface Ctx { + Logger log(); + Path dest(); + } + + public static abstract class ReportType implements Serializable { + private String name; + + /*private[api]*/ + ReportType(String name) {} + + public static final ReportType Console = new ConsoleModule(); + public static final FileReportType Html = new HtmlModule(); + public static final FileReportType Xml = new XmlModule(); + public static final FileReportType XmlCobertura = new XmlCoberturaModule(); + + /* private[api]*/ + static final class ConsoleModule extends ReportType implements Serializable { + /* private[api]*/ + ConsoleModule() { + super("Console"); + } + }; + + /* private[api]*/ + static final class HtmlModule extends FileReportType implements Serializable { + /* private[api]*/ + HtmlModule() { + super("Html", "htmlReport"); + } + }; + + /* private[api]*/ + static final class XmlModule extends FileReportType implements Serializable { + /* private[api]*/ + XmlModule() { + super("Xml", "xmlReport"); + } + } + + /* private[api]*/ + static final class XmlCoberturaModule extends FileReportType implements Serializable { + /* private[api]*/ + XmlCoberturaModule() { + super("XmlCobertura", "xmlCoberturaReport"); + } + } + + @Override + public String toString() { + return name; + } + } + + public static abstract class FileReportType extends ReportType implements Serializable { + private final String folderName; + + /*private[api]*/ + FileReportType(String name, String folderName) { + super(name); + this.folderName = folderName; + } + + public String folderName() { + return folderName; + } + } + + void report(ReportType reportType, Path[] sources, Path[] dataDirs, Path sourceRoot, Ctx ctx); + + static void makeAllDirs(Path path) throws IOException { + // Replicate behavior of `os.makeDir.all(path)` + if (Files.isDirectory(path) && Files.isSymbolicLink(path)) { + // do nothing + } else { + Files.createDirectories(path); + } + } + +} diff --git a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala index fba21cb2ccd2..e7824a266b04 100644 --- a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala +++ b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala @@ -3,7 +3,7 @@ package mill.contrib.scoverage import coursier.Repository import mill._ import mill.api.{Loose, PathRef, Result} -import mill.contrib.scoverage.api.ScoverageReportWorkerApi.ReportType +import mill.contrib.scoverage.api.ScoverageReportWorkerApi2.ReportType import mill.main.BuildInfo import mill.scalalib.api.ZincWorkerUtil import mill.scalalib.{Dep, DepSyntax, JavaModule, ScalaModule} diff --git a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReport.scala b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReport.scala index fd25e64e3daf..e7c6ed5670f9 100644 --- a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReport.scala +++ b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReport.scala @@ -1,6 +1,6 @@ package mill.contrib.scoverage -import mill.contrib.scoverage.api.ScoverageReportWorkerApi.ReportType +import mill.contrib.scoverage.api.ScoverageReportWorkerApi2.ReportType import mill.define.{Command, Module, Task} import mill.eval.Evaluator import mill.resolve.{Resolve, SelectMode} diff --git a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReportWorker.scala b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReportWorker.scala index 799ed317178c..600c90d3bb92 100644 --- a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReportWorker.scala +++ b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageReportWorker.scala @@ -2,13 +2,18 @@ package mill.contrib.scoverage import mill.{Agg, Task} import mill.api.{ClassLoader, Ctx, PathRef} -import mill.contrib.scoverage.api.ScoverageReportWorkerApi +import mill.contrib.scoverage.api.ScoverageReportWorkerApi2 import mill.define.{Discover, ExternalModule, Worker} +import ScoverageReportWorker.ScoverageReportWorkerApiBridge +import ScoverageReportWorkerApi2.ReportType +import ScoverageReportWorkerApi2.{Logger => ApiLogger} +import ScoverageReportWorkerApi2.{Ctx => ApiCtx} + class ScoverageReportWorker extends AutoCloseable { - private[this] var scoverageClCache = Option.empty[(Long, ClassLoader)] + private var scoverageClCache = Option.empty[(Long, ClassLoader)] - def bridge(classpath: Agg[PathRef])(implicit ctx: Ctx): ScoverageReportWorkerApi = { + def bridge(classpath: Agg[PathRef])(implicit ctx: Ctx): ScoverageReportWorkerApiBridge = { val classloaderSig = classpath.hashCode val cl = scoverageClCache match { @@ -24,11 +29,43 @@ class ScoverageReportWorker extends AutoCloseable { cl } - cl - .loadClass("mill.contrib.scoverage.worker.ScoverageReportWorkerImpl") - .getDeclaredConstructor() - .newInstance() - .asInstanceOf[api.ScoverageReportWorkerApi] + val worker = + cl + .loadClass("mill.contrib.scoverage.worker.ScoverageReportWorkerImpl") + .getDeclaredConstructor() + .newInstance() + .asInstanceOf[api.ScoverageReportWorkerApi2] + + def ctx0(implicit ctx: Ctx): ApiCtx = { + val logger = new ApiLogger { + def info(msg: String): Unit = ctx.log.info(msg) + def error(msg: String): Unit = ctx.log.error(msg) + def debug(msg: String): Unit = ctx.log.debug(msg) + } + new ApiCtx { + def log() = logger + def dest() = ctx.dest.toNIO + } + } + + new ScoverageReportWorkerApiBridge { + override def report( + reportType: ReportType, + sources: Seq[os.Path], + dataDirs: Seq[os.Path], + sourceRoot: os.Path + )(implicit + ctx: Ctx + ): Unit = { + worker.report( + reportType, + sources.map(_.toNIO).toArray, + dataDirs.map(_.toNIO).toArray, + sourceRoot.toNIO, + ctx0 + ) + } + } } override def close(): Unit = { @@ -37,6 +74,18 @@ class ScoverageReportWorker extends AutoCloseable { } object ScoverageReportWorker extends ExternalModule { + import ScoverageReportWorkerApi2.ReportType + + trait ScoverageReportWorkerApiBridge { + def report( + reportType: ReportType, + sources: Seq[os.Path], + dataDirs: Seq[os.Path], + sourceRoot: os.Path + )(implicit + ctx: Ctx + ): Unit + } def scoverageReportWorker: Worker[ScoverageReportWorker] = Task.Worker { new ScoverageReportWorker() } diff --git a/contrib/scoverage/worker2/src/mill/contrib/scoverage/worker/ScoverageReportWorkerImpl.scala b/contrib/scoverage/worker2/src/mill/contrib/scoverage/worker/ScoverageReportWorkerImpl.scala index a478a91c533a..1393af627f1a 100644 --- a/contrib/scoverage/worker2/src/mill/contrib/scoverage/worker/ScoverageReportWorkerImpl.scala +++ b/contrib/scoverage/worker2/src/mill/contrib/scoverage/worker/ScoverageReportWorkerImpl.scala @@ -1,42 +1,46 @@ package mill.contrib.scoverage.worker -import mill.contrib.scoverage.api.ScoverageReportWorkerApi import _root_.scoverage.reporter.{ CoberturaXmlWriter, CoverageAggregator, ScoverageHtmlWriter, ScoverageXmlWriter } -import mill.api.Ctx -import mill.contrib.scoverage.api.ScoverageReportWorkerApi.ReportType + +import mill.contrib.scoverage.api.ScoverageReportWorkerApi2 +import ScoverageReportWorkerApi2.ReportType +import ScoverageReportWorkerApi2.Ctx + +import java.nio.file.Path /** * Scoverage Worker for Scoverage 2.x */ -class ScoverageReportWorkerImpl extends ScoverageReportWorkerApi { +class ScoverageReportWorkerImpl extends ScoverageReportWorkerApi2 { override def report( reportType: ReportType, - sources: Seq[os.Path], - dataDirs: Seq[os.Path], - sourceRoot: os.Path - )(implicit ctx: Ctx): Unit = + sources: Array[Path], + dataDirs: Array[Path], + sourceRoot: Path, + ctx: Ctx + ): Unit = try { ctx.log.info(s"Processing coverage data for ${dataDirs.size} data locations") - CoverageAggregator.aggregate(dataDirs.map(_.toIO), sourceRoot.toIO) match { + CoverageAggregator.aggregate(dataDirs.map(_.toFile).toIndexedSeq, sourceRoot.toFile) match { case Some(coverage) => - val sourceFolders = sources.map(_.toIO) + val sourceFolders = sources.map(_.toFile).toIndexedSeq val folder = ctx.dest - os.makeDir.all(folder) + ScoverageReportWorkerApi2.makeAllDirs(folder) reportType match { case ReportType.Html => - new ScoverageHtmlWriter(sourceFolders, folder.toIO, None) + new ScoverageHtmlWriter(sourceFolders, folder.toFile, None) .write(coverage) case ReportType.Xml => - new ScoverageXmlWriter(sourceFolders, folder.toIO, false, None) + new ScoverageXmlWriter(sourceFolders, folder.toFile, false, None) .write(coverage) case ReportType.XmlCobertura => - new CoberturaXmlWriter(sourceFolders, folder.toIO, None) + new CoberturaXmlWriter(sourceFolders, folder.toFile, None) .write(coverage) case ReportType.Console => ctx.log.info(s"Statement coverage.: ${coverage.statementCoverageFormatted}%") diff --git a/contrib/twirllib/src/mill/twirllib/TwirlModule.scala b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala index c2d6fad03b86..0c3269e78c2d 100644 --- a/contrib/twirllib/src/mill/twirllib/TwirlModule.scala +++ b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala @@ -33,7 +33,7 @@ trait TwirlModule extends mill.Module { twirlModule => * Replicate the logic from twirl build, * see: https://github.com/playframework/twirl/blob/2.0.1/build.sbt#L12-L17 */ - private def scalaParserCombinatorsVersion: T[String] = twirlScalaVersion.map { + private def scalaParserCombinatorsVersion: Task[String] = twirlScalaVersion.map { case v if v.startsWith("2.") => "1.1.2" case _ => "2.3.0" } @@ -57,7 +57,7 @@ trait TwirlModule extends mill.Module { twirlModule => * @since Mill after 0.10.5 */ trait TwirlResolver extends CoursierModule { - override def resolveCoursierDependency: Task[Dep => Dependency] = Task.Anon { d: Dep => + override def resolveCoursierDependency: Task[Dep => Dependency] = Task.Anon { (d: Dep) => Lib.depToDependency(d, twirlScalaVersion()) } diff --git a/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala index a8094cc725b8..d881936fab24 100644 --- a/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala +++ b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala @@ -7,6 +7,7 @@ import utest.{TestSuite, Tests, assert, _} trait HelloWorldTests extends TestSuite { val testTwirlVersion: String + val wildcard: String trait HelloWorldModule extends mill.twirllib.TwirlModule { def twirlVersion = testTwirlVersion @@ -39,8 +40,8 @@ trait HelloWorldTests extends TestSuite { ) def expectedDefaultImports: Seq[String] = Seq( - "import _root_.play.twirl.api.TwirlFeatureImports._", - "import _root_.play.twirl.api.TwirlHelperImports._", + s"import _root_.play.twirl.api.TwirlFeatureImports.$wildcard", + s"import _root_.play.twirl.api.TwirlHelperImports.$wildcard", "import _root_.play.twirl.api.Html", "import _root_.play.twirl.api.JavaScript", "import _root_.play.twirl.api.Txt", @@ -48,8 +49,8 @@ trait HelloWorldTests extends TestSuite { ) def testAdditionalImports: Seq[String] = Seq( - "mill.twirl.test.AdditionalImport1._", - "mill.twirl.test.AdditionalImport2._" + s"mill.twirl.test.AdditionalImport1.$wildcard", + s"mill.twirl.test.AdditionalImport2.$wildcard" ) def testConstructorAnnotations = Seq( @@ -159,13 +160,17 @@ trait HelloWorldTests extends TestSuite { object HelloWorldTests1_3 extends HelloWorldTests { override val testTwirlVersion = "1.3.16" + override val wildcard = "_" } object HelloWorldTests1_5 extends HelloWorldTests { override val testTwirlVersion = "1.5.2" + override val wildcard = "_" } object HelloWorldTests1_6 extends HelloWorldTests { override val testTwirlVersion = "1.6.2" + override val wildcard = "*" } object HelloWorldTests2_0 extends HelloWorldTests { override val testTwirlVersion = "2.0.1" + override val wildcard = "*" } diff --git a/example/thirdparty/mockito/build.mill b/example/thirdparty/mockito/build.mill index 0af38beb6ad1..9eab3b2ab0be 100644 --- a/example/thirdparty/mockito/build.mill +++ b/example/thirdparty/mockito/build.mill @@ -42,11 +42,20 @@ trait MockitoModule extends MavenModule{ def testRuntimeIvyDeps: T[Agg[Dep]] = Agg.empty[Dep] def testFramework = "com.novocode.junit.JUnitFramework" def testForkArgs: T[Seq[String]] = Seq.empty[String] + + def testFilteredSources: T[Seq[PathRef]] = Task { Seq.empty } + object test extends MavenTests{ def moduleDeps = super.moduleDeps ++ MockitoModule.this.testModuleDeps def testFramework = MockitoModule.this.testFramework def runIvyDeps = testRuntimeIvyDeps() def forkArgs = testForkArgs() + def allSourceFiles = Task { + val base = super.allSourceFiles() + val filtered = testFilteredSources().toSet + if (filtered.isEmpty) base + else base.filterNot(filtered.contains) + } def ivyDeps = testIvyDeps() ++ Agg( @@ -85,6 +94,11 @@ object `package` extends RootModule with MockitoModule{ super.resources() ++ Seq(PathRef(Task.dest)) } + def testFilteredSources: T[Seq[PathRef]] = Task { + // test `add_listeners_concurrently_sanity_check` is flaky + Seq(PathRef(millSourcePath / "src/test/java/org/mockitousage/debugging/StubbingLookupListenerCallbackTest.java")) + } + object subprojects extends Module { object android extends MockitoModule { def moduleDeps = Seq(build) diff --git a/example/thirdparty/netty/build.mill b/example/thirdparty/netty/build.mill index f7b105790344..b9a1a7f30996 100644 --- a/example/thirdparty/netty/build.mill +++ b/example/thirdparty/netty/build.mill @@ -253,8 +253,8 @@ object common extends NettyModule{ val shell = new groovy.lang.GroovyShell() val context = new java.util.HashMap[String, Object] - context.put("collection.template.dir", Task.workspace + "/common/src/main/templates") - context.put("collection.template.test.dir", Task.workspace + "/common/src/test/templates") + context.put("collection.template.dir", s"${Task.workspace}/common/src/main/templates") + context.put("collection.template.test.dir", s"${Task.workspace}/common/src/test/templates") context.put("collection.src.dir", (Task.dest / "src").toString) context.put("collection.testsrc.dir", (Task.dest / "testsrc").toString) shell.setProperty("properties", context) diff --git a/integration/invalidation/multi-level-editing/resources/mill-build/mill-build/build.mill b/integration/invalidation/multi-level-editing/resources/mill-build/mill-build/build.mill index 7d6f134d94e7..4efe9a06fcdf 100644 --- a/integration/invalidation/multi-level-editing/resources/mill-build/mill-build/build.mill +++ b/integration/invalidation/multi-level-editing/resources/mill-build/mill-build/build.mill @@ -8,7 +8,7 @@ object `package` extends MillBuildRootModule { Task.dest / "MetaConstant.scala", """package constant |object MetaConstant{ - | def scalatagsVersion = "0.8.2" + | def scalatagsVersion = "0.13.1" |} |""".stripMargin ) diff --git a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala index ba9554d6c7a7..c799d0f65876 100644 --- a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala +++ b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala @@ -87,7 +87,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { assert(res.isSuccess == false) // Prepend a "\n" to allow callsites to use "\n" to test for start of // line, even though the first line doesn't have a "\n" at the start - val err = "\n" + res.err + val err = "```\n" + res.err + "\n```" for (expected <- expectedSnippets) { assert(err.contains(expected)) } @@ -130,7 +130,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { test("validEdits") - integrationTest { tester => import tester._ - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), @@ -143,7 +143,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { checkChangedClassloaders(tester, null, true, true, true) modifyFile(workspacePath / "foo/src/Example.scala", _.replace("!", "?")) - runAssertSuccess(tester, "

hello

world

0.8.2

?") + runAssertSuccess(tester, "

hello

world

0.13.1

?") checkWatchedFiles( tester, fooPaths(tester), @@ -155,7 +155,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { checkChangedClassloaders(tester, null, false, false, false) modifyFile(workspacePath / "build.mill", _.replace("hello", "HELLO")) - runAssertSuccess(tester, "

HELLO

world

0.8.2

?") + runAssertSuccess(tester, "

HELLO

world

0.13.1

?") checkWatchedFiles( tester, fooPaths(tester), @@ -169,7 +169,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { workspacePath / "mill-build/build.mill", _.replace("def scalatagsVersion = ", "def scalatagsVersion = \"changed-\" + ") ) - runAssertSuccess(tester, "

HELLO

world

changed-0.8.2

?") + runAssertSuccess(tester, "

HELLO

world

changed-0.13.1

?") checkWatchedFiles( tester, fooPaths(tester), @@ -181,7 +181,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { modifyFile( workspacePath / "mill-build/mill-build/build.mill", - _.replace("0.8.2", "0.12.0") + _.replace("0.13.1", "0.12.0") ) runAssertSuccess(tester, "

HELLO

world

changed-0.12.0

?") checkWatchedFiles( @@ -195,9 +195,9 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { modifyFile( workspacePath / "mill-build/mill-build/build.mill", - _.replace("0.12.0", "0.8.2") + _.replace("0.12.0", "0.13.1") ) - runAssertSuccess(tester, "

HELLO

world

changed-0.8.2

?") + runAssertSuccess(tester, "

HELLO

world

changed-0.13.1

?") checkWatchedFiles( tester, fooPaths(tester), @@ -211,7 +211,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { workspacePath / "mill-build/build.mill", _.replace("def scalatagsVersion = \"changed-\" + ", "def scalatagsVersion = ") ) - runAssertSuccess(tester, "

HELLO

world

0.8.2

?") + runAssertSuccess(tester, "

HELLO

world

0.13.1

?") checkWatchedFiles( tester, fooPaths(tester), @@ -222,7 +222,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { checkChangedClassloaders(tester, null, true, true, false) modifyFile(workspacePath / "build.mill", _.replace("HELLO", "hello")) - runAssertSuccess(tester, "

hello

world

0.8.2

?") + runAssertSuccess(tester, "

hello

world

0.13.1

?") checkWatchedFiles( tester, fooPaths(tester), @@ -233,7 +233,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { checkChangedClassloaders(tester, null, true, false, false) modifyFile(workspacePath / "foo/src/Example.scala", _.replace("?", "!")) - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), @@ -252,7 +252,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { def fixParseError(p: os.Path) = modifyFile(p, _.replace("extendx", "extends")) - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), @@ -300,7 +300,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { checkChangedClassloaders(tester, null, null, null, null) fixParseError(workspacePath / "build.mill") - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), @@ -319,7 +319,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { def fixCompileError(p: os.Path) = modifyFile(p, _.replace("import doesnt.exist", "")) - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), @@ -336,7 +336,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { // Ensure the file path in the compile error is properly adjusted to point // at the original source file and not the generated file (workspacePath / "build.mill").toString, - "not found: value doesnt" + "Not found: doesnt" ) checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, false, false) @@ -346,7 +346,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/build.mill").toString, - "not found: object doesnt" + "Not found: doesnt" ) checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, false) @@ -356,7 +356,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/mill-build/build.mill").toString, - "not found: object doesnt" + "Not found: doesnt" ) checkWatchedFiles(tester, Nil, Nil, Nil, buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, null) @@ -366,7 +366,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/build.mill").toString, - "not found: object doesnt" + "Not found: doesnt" ) checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, true) @@ -376,13 +376,13 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "build.mill").toString, - "not found: value doesnt" + "Not found: doesnt" ) checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, true, false) fixCompileError(workspacePath / "build.mill") - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), @@ -407,7 +407,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { def fixRuntimeError(p: os.Path) = modifyFile(p, _.replaceFirst(Regex.quote(runErrorSnippet), "\\{")) - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), @@ -475,7 +475,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { checkChangedClassloaders(tester, null, true, true, false) fixRuntimeError(workspacePath / "build.mill") - runAssertSuccess(tester, "

hello

world

0.8.2

!") + runAssertSuccess(tester, "

hello

world

0.13.1

!") checkWatchedFiles( tester, fooPaths(tester), From 9cd9cf60487f2be328e90bbfb3c47b1bb5781076 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 02:46:57 +0200 Subject: [PATCH 02/13] wip --- build.mill | 1 + main/api/src/mill/api/AggWrapper.scala | 19 ++++---- main/api/src/mill/api/ClassLoader.scala | 2 +- main/api/src/mill/api/Ctx.scala | 8 ++-- main/api/src/mill/api/FixSizedCache.scala | 2 +- main/api/src/mill/api/JarOps.scala | 6 +-- main/api/src/mill/api/JsonFormatters.scala | 2 +- main/api/src/mill/api/KeyedLockedCache.scala | 2 +- main/api/src/mill/api/PathRef.scala | 6 ++- main/api/src/mill/api/Result.scala | 18 ++++--- main/api/src/mill/api/Retry.scala | 4 +- main/api/src/mill/api/SystemStreams.scala | 6 +-- main/codesig/package.mill | 3 +- main/codesig/src/JvmModel.scala | 2 +- main/codesig/src/ResolvedCalls.scala | 4 +- main/codesig/src/SpanningForest.scala | 6 ++- .../basic/17-scala-lambda/src/Hello.scala | 7 ++- .../src/Hello.scala | 5 +- .../6-classes-misc-scala/src/Hello.scala | 2 +- .../8-linked-list-scala/src/Hello.scala | 4 +- .../realistic/5-parser/src/Hello.scala | 32 +++++++++++-- .../test/src/mill/define/BasePathTests.scala | 20 ++++---- main/eval/src/mill/eval/EvaluatorCore.scala | 37 ++++++++------- main/eval/src/mill/eval/GroupEvaluator.scala | 4 +- .../test/src/mill/eval/EvaluationTests.scala | 47 ++++++++++--------- main/init/src/mill/init/InitModule.scala | 5 +- main/package.mill | 18 ++++++- .../src/mill/resolve/ExpandBraces.scala | 4 +- main/resolve/src/mill/resolve/ParseArgs.scala | 2 +- .../mill/resolve/ResolveNotFoundHandler.scala | 6 +-- main/server/src/mill/main/server/Server.scala | 3 +- main/src/mill/main/MainModule.scala | 4 +- main/util/src/mill/util/PrefixLogger.scala | 6 +-- 33 files changed, 182 insertions(+), 115 deletions(-) diff --git a/build.mill b/build.mill index f4a9b0f2e24d..151635a59a4e 100644 --- a/build.mill +++ b/build.mill @@ -56,6 +56,7 @@ object Deps { // When updating, run "Publish Bridges" Github Actions for the new version // and then add to it `bridgeScalaVersions` val scalaVersion = "2.13.14" + val scala2Version = "2.13.14" // The Scala 2.12.x version to use for some workers val workerScalaVersion212 = "2.12.19" diff --git a/main/api/src/mill/api/AggWrapper.scala b/main/api/src/mill/api/AggWrapper.scala index 063828464378..31f27082915b 100644 --- a/main/api/src/mill/api/AggWrapper.scala +++ b/main/api/src/mill/api/AggWrapper.scala @@ -33,11 +33,11 @@ private[mill] sealed class AggWrapper(strictUniqueness: Boolean) { def map[T](f: V => T): Agg[T] def filter(f: V => Boolean): Agg[V] - def collect[T](f: PartialFunction[V, T]): Agg[T] - def zipWithIndex: Agg[(V, Int)] + override def collect[T](f: PartialFunction[V, T]): Agg[T] = super.collect(f) + override def zipWithIndex: Agg[(V, Int)] = super.zipWithIndex def reverse: Agg[V] def zip[T](other: Agg[T]): Agg[(V, T)] - def ++[T >: V](other: IterableOnce[T]): Agg[T] + // def ++[T >: V](other: IterableOnce[T]): Agg[T] // error overriding final method ++ in trait IterableOps def length: Int def isEmpty: Boolean def foreach[U](f: V => U): Unit @@ -85,16 +85,15 @@ private[mill] sealed class AggWrapper(strictUniqueness: Boolean) { Mutable.newBuilder[V] } - private[this] val set0 = mutable.LinkedHashSet.empty[V] + private val set0 = mutable.LinkedHashSet.empty[V] def contains(v: V): Boolean = set0.contains(v) def coll: Mutable[V] = this - override def toIterable: Iterable[V] = set0.toIterable + override def toIterable: Iterable[V] = set0 def append(v: V): AnyVal = { if (!contains(v)) { - set0.add(v) - + return set0.add(v) } else if (strictUniqueness) { throw new Exception("Duplicated item inserted into OrderedSet: " + v) } @@ -118,7 +117,9 @@ private[mill] sealed class AggWrapper(strictUniqueness: Boolean) { override def filter(f: V => Boolean): Mutable[V] = { val output = new Agg.Mutable[V] - for (i <- items) if (f(i)) output.append(i) + for (i <- items) if (f(i)) { + val _ = output.append(i) + } output } @@ -148,7 +149,7 @@ private[mill] sealed class AggWrapper(strictUniqueness: Boolean) { def iterator: Iterator[V] = items override def hashCode(): Int = items.map(_.hashCode()).sum override def equals(other: Any): Boolean = other match { - case s: Agg[_] => items.sameElements(s.items) + case s: Agg[?] => items.sameElements(s.items) case _ => super.equals(other) } override def toString: String = items.mkString("Agg(", ", ", ")") diff --git a/main/api/src/mill/api/ClassLoader.scala b/main/api/src/mill/api/ClassLoader.scala index 6f2b5ec7f2bb..5db97159d63a 100644 --- a/main/api/src/mill/api/ClassLoader.scala +++ b/main/api/src/mill/api/ClassLoader.scala @@ -26,7 +26,7 @@ object ClassLoader { makeUrls(urls).toArray, refinePlatformParent(parent) ) { - override def findClass(name: String): Class[_] = { + override def findClass(name: String): Class[?] = { if (sharedPrefixes.exists(name.startsWith)) { logger.foreach( _.debug(s"About to load class [${name}] from shared classloader [${sharedLoader}]") diff --git a/main/api/src/mill/api/Ctx.scala b/main/api/src/mill/api/Ctx.scala index ca08069896b0..59ad59d3d67e 100644 --- a/main/api/src/mill/api/Ctx.scala +++ b/main/api/src/mill/api/Ctx.scala @@ -73,7 +73,7 @@ object Ctx { } trait Args { - def args: IndexedSeq[_] + def args: IndexedSeq[?] } /** @@ -167,7 +167,7 @@ object Ctx { * implementation of a `Task`. */ class Ctx( - val args: IndexedSeq[_], + val args: IndexedSeq[?], dest0: () => os.Path, val log: Logger, val home: os.Path, @@ -185,7 +185,7 @@ class Ctx( with Ctx.Workspace { def this( - args: IndexedSeq[_], + args: IndexedSeq[?], dest0: () => os.Path, log: Logger, home: os.Path, @@ -194,7 +194,7 @@ class Ctx( testReporter: TestReporter, workspace: os.Path ) = { - this(args, dest0, log, home, env, reporter, testReporter, workspace, i => ???, null) + this(args, dest0, log, home, env, reporter, testReporter, workspace, _ => ???, null) } def dest: os.Path = dest0() def arg[T](index: Int): T = { diff --git a/main/api/src/mill/api/FixSizedCache.scala b/main/api/src/mill/api/FixSizedCache.scala index 5d71874246b6..0ba0f2a12e5d 100644 --- a/main/api/src/mill/api/FixSizedCache.scala +++ b/main/api/src/mill/api/FixSizedCache.scala @@ -15,7 +15,7 @@ import java.util.concurrent.{ConcurrentHashMap, Semaphore} class FixSizedCache[T](perKeySize: Int) extends KeyedLockedCache[T] { // Cache Key -> (Semaphore, Array of cached elements) - private[this] val keyToCache: ConcurrentHashMap[Long, (Semaphore, Array[(Boolean, Option[T])])] = + private val keyToCache: ConcurrentHashMap[Long, (Semaphore, Array[(Boolean, Option[T])])] = new ConcurrentHashMap override def withCachedValue[V](key: Long)(f: => T)(f2: T => V): V = { diff --git a/main/api/src/mill/api/JarOps.scala b/main/api/src/mill/api/JarOps.scala index 9f2e0d2a7376..540c706ca29d 100644 --- a/main/api/src/mill/api/JarOps.scala +++ b/main/api/src/mill/api/JarOps.scala @@ -73,7 +73,7 @@ trait JarOps { os.remove.all(jar) val seen = mutable.Set.empty[os.RelPath] - seen.add(os.sub / "META-INF/MANIFEST.MF") + val _ = seen.add(os.sub / "META-INF/MANIFEST.MF") val jarStream = new JarOutputStream( new BufferedOutputStream(new FileOutputStream(jar.toIO)), @@ -84,7 +84,7 @@ trait JarOps { assert(inputPaths.iterator.forall(os.exists(_))) if (includeDirs) { - seen.add(os.sub / "META-INF") + val _ = seen.add(os.sub / "META-INF") val entry = new JarEntry("META-INF/") entry.setTime(curTime) jarStream.putNextEntry(entry) @@ -99,7 +99,7 @@ trait JarOps { else os.walk(p).map(sub => (sub, sub.subRelativeTo(p))).sorted if (includeDirs || os.isFile(file)) && !seen(mapping) && fileFilter(p, mapping) } { - seen.add(mapping) + val _ = seen.add(mapping) val name = mapping.toString() + (if (os.isDir(file)) "/" else "") val entry = new JarEntry(name) entry.setTime(mTime(file)) diff --git a/main/api/src/mill/api/JsonFormatters.scala b/main/api/src/mill/api/JsonFormatters.scala index dda6a1c3cc1b..bf1b448955fd 100644 --- a/main/api/src/mill/api/JsonFormatters.scala +++ b/main/api/src/mill/api/JsonFormatters.scala @@ -62,7 +62,7 @@ trait JsonFormatters { ) ) - implicit def enumFormat[T <: java.lang.Enum[_]: ClassTag]: RW[T] = + implicit def enumFormat[T <: java.lang.Enum[?]: ClassTag]: RW[T] = upickle.default.readwriter[String].bimap( _.name(), (s: String) => diff --git a/main/api/src/mill/api/KeyedLockedCache.scala b/main/api/src/mill/api/KeyedLockedCache.scala index 7a8fc21a92fd..3ee62796f3cd 100644 --- a/main/api/src/mill/api/KeyedLockedCache.scala +++ b/main/api/src/mill/api/KeyedLockedCache.scala @@ -11,7 +11,7 @@ trait KeyedLockedCache[T] { object KeyedLockedCache { class RandomBoundedCache[T](hotParallelism: Int, coldCacheSize: Int) extends KeyedLockedCache[T] { - private[this] val random = new scala.util.Random(313373) + private val random = new scala.util.Random(313373) val available = new java.util.concurrent.Semaphore(hotParallelism) // Awful asymptotic complexity, but our caches are tiny n < 10 so it doesn't matter diff --git a/main/api/src/mill/api/PathRef.scala b/main/api/src/mill/api/PathRef.scala index ad1ae5a44eb0..483efa569c17 100644 --- a/main/api/src/mill/api/PathRef.scala +++ b/main/api/src/mill/api/PathRef.scala @@ -1,10 +1,13 @@ package mill.api +import scala.language.implicitConversions + import java.nio.{file => jnio} import java.security.{DigestOutputStream, MessageDigest} import java.util.concurrent.ConcurrentHashMap import scala.util.{DynamicVariable, Using} import upickle.default.{ReadWriter => RW} +import scala.annotation.nowarn /** * A wrapper around `os.Path` that calculates it's hashcode based @@ -69,7 +72,7 @@ object PathRef { if (pathRef.sig != changedSig) { throw new PathRefValidationException(pathRef) } - map.put(mapKey(pathRef), pathRef) + val _ = map.put(mapKey(pathRef), pathRef) } } def clear(): Unit = map.clear() @@ -197,6 +200,7 @@ object PathRef { ) // scalafix:off; we want to hide the unapply method + @nowarn("msg=unused") private def unapply(pathRef: PathRef): Option[(os.Path, Boolean, Int, Revalidate)] = { Some((pathRef.path, pathRef.quick, pathRef.sig, pathRef.revalidate)) } diff --git a/main/api/src/mill/api/Result.scala b/main/api/src/mill/api/Result.scala index ad7af1e051bf..afe73a5c2d1e 100644 --- a/main/api/src/mill/api/Result.scala +++ b/main/api/src/mill/api/Result.scala @@ -13,9 +13,10 @@ sealed trait Result[+T] { def flatMap[V](f: T => Result[V]): Result[V] def asSuccess: Option[Result.Success[T]] = None def asFailing: Option[Result.Failing[T]] = None - def getOrThrow: T = this match { + def getOrThrow: T = (this: @unchecked) match { case Result.Success(v) => v - case f: Result.Failing[_] => throw f + case f: Result.Failing[?] => throw f + // no cases for Skipped or Aborted? } } @@ -95,10 +96,15 @@ object Result { current = current.head.getCause :: current } current.reverse - .flatMap(ex => - Seq(ex.toString) ++ - ex.getStackTrace.dropRight(outerStack.value.length).map(" " + _) - ) + .flatMap { ex => + val elements = ex.getStackTrace.dropRight(outerStack.value.length) + val formatted = + // for some reason .map without the explicit ArrayOps conversion doesn't work, + // and results in `Result[String]` instead of `Array[String]` + new scala.collection.ArrayOps(elements).map(" " + _) + Seq(ex.toString) ++ formatted + + } .mkString("\n") } } diff --git a/main/api/src/mill/api/Retry.scala b/main/api/src/mill/api/Retry.scala index 2398d4e87e79..ca35b0537f73 100644 --- a/main/api/src/mill/api/Retry.scala +++ b/main/api/src/mill/api/Retry.scala @@ -38,9 +38,9 @@ case class Retry( if (timeoutMillis == -1) t(retryCount) else { val result = Promise[T] - val thread = new Thread(() => { + val thread = new Thread({ () => result.complete(scala.util.Try(t(retryCount))) - }) + }: Runnable) thread.start() Await.result(result.future, Duration.apply(timeoutMillis, TimeUnit.MILLISECONDS)) } diff --git a/main/api/src/mill/api/SystemStreams.scala b/main/api/src/mill/api/SystemStreams.scala index e42b34d80ed9..3912eb57042d 100644 --- a/main/api/src/mill/api/SystemStreams.scala +++ b/main/api/src/mill/api/SystemStreams.scala @@ -132,9 +132,9 @@ object SystemStreams { def setTopLevelSystemStreamProxy(): Unit = { // Make sure to initialize `Console` to cache references to the original // `System.{in,out,err}` streams before we redirect them - Console.out - Console.err - Console.in + val _ = Console.out + val _ = Console.err + val _ = Console.in System.setIn(ThreadLocalStreams.In) System.setOut(ThreadLocalStreams.Out) System.setErr(ThreadLocalStreams.Err) diff --git a/main/codesig/package.mill b/main/codesig/package.mill index 51c622e50544..7e0120def83e 100644 --- a/main/codesig/package.mill +++ b/main/codesig/package.mill @@ -47,7 +47,8 @@ object `package` extends RootModule with build.MillPublishScalaModule { build.Deps.mainargs, build.Deps.requests, build.Deps.osLib, - build.Deps.upickle + build.Deps.upickle, + build.Deps.sourcecode ) } } diff --git a/main/codesig/src/JvmModel.scala b/main/codesig/src/JvmModel.scala index 00c36c8fd316..e63eeffa937f 100644 --- a/main/codesig/src/JvmModel.scala +++ b/main/codesig/src/JvmModel.scala @@ -139,7 +139,7 @@ object JvmModel { sealed class Prim(val pretty: String) extends JType - object Prim extends { + object Prim { def read(s: String): Prim = all(s(0)) val all: Map[Char, Prim] = Map( diff --git a/main/codesig/src/ResolvedCalls.scala b/main/codesig/src/ResolvedCalls.scala index 7b2fe32a26dd..6bb5b5698f7a 100644 --- a/main/codesig/src/ResolvedCalls.scala +++ b/main/codesig/src/ResolvedCalls.scala @@ -113,7 +113,9 @@ object ResolvedCalls { val externalSamDefiners = externalSummary .directMethods .map { case (k, v) => (k, v.collect { case (sig, true) => sig }) } - .collect { case (k, Seq(v)) => (k, v) } + .collect { case (k, Seq(v)) => + (k, v) + } // Scala 3.5.0-RC6 - can not infer MethodSig here val allSamDefiners = localSamDefiners ++ externalSamDefiners diff --git a/main/codesig/src/SpanningForest.scala b/main/codesig/src/SpanningForest.scala index 115d60b35548..dd870bd48270 100644 --- a/main/codesig/src/SpanningForest.scala +++ b/main/codesig/src/SpanningForest.scala @@ -36,7 +36,11 @@ object SpanningForest { .groupMap(_._1)(_._2) ResolvedCalls.breadthFirst(rootChangedNodeIndices) { index => - val nextIndices = downstreamGraphEdges.getOrElse(index, Array()) + val nextIndices = + downstreamGraphEdges.getOrElse( + index, + Array[Int]() + ) // needed to add explicit type for Scala 3.5.0-RC6 // We build up the spanningForest during a normal breadth first search, // using the `nodeMapping` to quickly find an vertice's tree node so we // can add children to it. We need to duplicate the `seen.contains` logic diff --git a/main/codesig/test/cases/callgraph/basic/17-scala-lambda/src/Hello.scala b/main/codesig/test/cases/callgraph/basic/17-scala-lambda/src/Hello.scala index 45fdc0c8195c..d9c7a6141ff0 100644 --- a/main/codesig/test/cases/callgraph/basic/17-scala-lambda/src/Hello.scala +++ b/main/codesig/test/cases/callgraph/basic/17-scala-lambda/src/Hello.scala @@ -1,9 +1,14 @@ package hello object Hello { + + trait MyFunction0[T] { + def apply(): T + } + def main(): Int = { - val foo = () => used() + val foo: MyFunction0[Int] = () => used() foo() } def used(): Int = 2 diff --git a/main/codesig/test/cases/callgraph/complicated/13-iterator-inherit-external-filter-scala/src/Hello.scala b/main/codesig/test/cases/callgraph/complicated/13-iterator-inherit-external-filter-scala/src/Hello.scala index 7096870a717b..6861bc5ecf27 100644 --- a/main/codesig/test/cases/callgraph/complicated/13-iterator-inherit-external-filter-scala/src/Hello.scala +++ b/main/codesig/test/cases/callgraph/complicated/13-iterator-inherit-external-filter-scala/src/Hello.scala @@ -26,10 +26,11 @@ object Hello { private[this] var hdDefined: Boolean = false def hasNext: Boolean = hdDefined || { - do { + while ({ if (!parent.hasNext) return false hd = parent.next() - } while (!pred(hd)) + !pred(hd) + }) {} hdDefined = true true } diff --git a/main/codesig/test/cases/callgraph/complicated/6-classes-misc-scala/src/Hello.scala b/main/codesig/test/cases/callgraph/complicated/6-classes-misc-scala/src/Hello.scala index 39896097bae4..a724d7d6d3bd 100644 --- a/main/codesig/test/cases/callgraph/complicated/6-classes-misc-scala/src/Hello.scala +++ b/main/codesig/test/cases/callgraph/complicated/6-classes-misc-scala/src/Hello.scala @@ -32,7 +32,7 @@ class DoubleDetMatrix(aa: Float, ab: Float, ba: Float, bb: Float) } class LinkedList { - def push(i: Int) { + def push(i: Int): Unit = { val n = new Inner(i, head) head = n } diff --git a/main/codesig/test/cases/callgraph/complicated/8-linked-list-scala/src/Hello.scala b/main/codesig/test/cases/callgraph/complicated/8-linked-list-scala/src/Hello.scala index 061c4c14aebc..5235986b9203 100644 --- a/main/codesig/test/cases/callgraph/complicated/8-linked-list-scala/src/Hello.scala +++ b/main/codesig/test/cases/callgraph/complicated/8-linked-list-scala/src/Hello.scala @@ -9,7 +9,7 @@ object Hello { def head: A def tail: TestList[A] - def foreach[U](f: A => U) { + def foreach[U](f: A => U): Unit = { var these = this while (!these.isEmpty) { f(these.head) @@ -21,7 +21,7 @@ object Hello { object TestNil extends TestList[Nothing] { def isEmpty = true def head = throw new Exception() - def tail = throw new Exception() + override def tail: Nothing = throw new Exception() } class TestCons[B](val head: B, val tl: TestList[B]) extends TestList[B] { diff --git a/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala b/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala index 1fb9a5a8a10d..334525b900e0 100644 --- a/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala +++ b/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala @@ -6,15 +6,15 @@ class Word(s: String) extends Phrase class Pair(lhs: Phrase, rhs: Phrase) extends Phrase object Parser { - def prefix[_: P] = P("hello" | "goodbye").!.map(new Word(_)) + def prefix[_X: P] = P("hello" | "goodbye").!.map(new Word(_)) - def suffix[_: P] = P("world" | "seattle").!.map(new Word(_)) + def suffix[_X: P] = P("world" | "seattle").!.map(new Word(_)) - def ws[_: P] = P(" ".rep(1)) + def ws[_X: P] = P(" ".rep(1)) - def parened[_: P] = P("(" ~ parser ~ ")") + def parened[_X: P] = P("(" ~ parser ~ ")") - def parser[_: P]: P[Phrase] = P((parened | prefix) ~ ws ~ (parened | suffix)).map { + def parser[_X: P]: P[Phrase] = P((parened | prefix) ~ ws ~ (parened | suffix)).map { case (lhs, rhs) => new Pair(lhs, rhs) } } @@ -24,6 +24,21 @@ object Parser { "hello.Parser$#parened(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Parser$#parser(fastparse.ParsingRun)fastparse.ParsingRun" ], + "hello.Parser$#parse0$proxy8$1(fastparse.ParsingRun)fastparse.ParsingRun": [ + "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" + ], + "hello.Parser$#parse0$proxy9$1(fastparse.ParsingRun)fastparse.ParsingRun": [ + "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" + ], + "hello.Parser$#parse0$proxy9$2(fastparse.ParsingRun)fastparse.ParsingRun": [ + "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" + ], + "hello.Parser$#parse0$proxy9$3(fastparse.ParsingRun)fastparse.ParsingRun": [ + "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" + ], + "hello.Parser$#parse0$proxy9$4(fastparse.ParsingRun)fastparse.ParsingRun": [ + "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" + ], "hello.Parser$#parser(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Pair#(hello.Phrase,hello.Phrase)void", "hello.Parser$#parened(fastparse.ParsingRun)fastparse.ParsingRun", @@ -34,9 +49,16 @@ object Parser { "hello.Parser$#prefix(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Word#(java.lang.String)void" ], + "hello.Parser$#rec$1(fastparse.ParsingRun,int,fastparse.Implicits$Repeater,java.lang.Object,fastparse.ParsingRun,int,int,boolean,boolean,fastparse.internal.Msgs,fastparse.internal.Msgs)fastparse.ParsingRun": [ + "hello.Parser$#end$1(int,fastparse.ParsingRun,fastparse.Implicits$Repeater,java.lang.Object,int,int,int,boolean)fastparse.ParsingRun", + "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" + ], "hello.Parser$#suffix(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Word#(java.lang.String)void" ], + "hello.Parser$#ws(fastparse.ParsingRun)fastparse.ParsingRun": [ + "hello.Parser$#rec$1(fastparse.ParsingRun,int,fastparse.Implicits$Repeater,java.lang.Object,fastparse.ParsingRun,int,int,boolean,boolean,fastparse.internal.Msgs,fastparse.internal.Msgs)fastparse.ParsingRun" + ], "hello.Parser.parened(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Parser$#()void", "hello.Parser$#parened(fastparse.ParsingRun)fastparse.ParsingRun" diff --git a/main/define/test/src/mill/define/BasePathTests.scala b/main/define/test/src/mill/define/BasePathTests.scala index dce543ca02ba..55901cb9778a 100644 --- a/main/define/test/src/mill/define/BasePathTests.scala +++ b/main/define/test/src/mill/define/BasePathTests.scala @@ -5,6 +5,17 @@ import mill.testkit.TestBaseModule import utest._ object BasePathTests extends TestSuite { + + object overriddenBasePath extends TestBaseModule { + override def millSourcePath = os.pwd / "overriddenBasePathRootValue" + object nested extends Module { + override def millSourcePath = super.millSourcePath / "overriddenBasePathNested" + object nested extends Module { + override def millSourcePath = super.millSourcePath / "overriddenBasePathDoubleNested" + } + } + } + val testGraphs = new TestGraphs val tests = Tests { def checkMillSourcePath[T <: Module](m: T)(f: T => Module, segments: String*): Unit = { @@ -54,15 +65,6 @@ object BasePathTests extends TestSuite { checkMillSourcePath(TestGraphs.nestedCrosses)(_.cross("210").cross2("js"), "cross", "cross2") } test("overridden") { - object overriddenBasePath extends TestBaseModule { - override def millSourcePath = os.pwd / "overriddenBasePathRootValue" - object nested extends Module { - override def millSourcePath = super.millSourcePath / "overriddenBasePathNested" - object nested extends Module { - override def millSourcePath = super.millSourcePath / "overriddenBasePathDoubleNested" - } - } - } assert( overriddenBasePath.millSourcePath == os.pwd / "overriddenBasePathRootValue", overriddenBasePath.nested.millSourcePath == os.pwd / "overriddenBasePathRootValue/nested/overriddenBasePathNested", diff --git a/main/eval/src/mill/eval/EvaluatorCore.scala b/main/eval/src/mill/eval/EvaluatorCore.scala index bfc257316862..fdb2cfbcea45 100644 --- a/main/eval/src/mill/eval/EvaluatorCore.scala +++ b/main/eval/src/mill/eval/EvaluatorCore.scala @@ -265,10 +265,10 @@ private[mill] trait EvaluatorCore extends GroupEvaluator { c.getInterfaces.iterator.flatMap(resolveTransitiveParents) } - val classToTransitiveClasses = sortedGroups + val classToTransitiveClasses: Map[Class[?], IndexedSeq[Class[?]]] = sortedGroups .values() .flatten - .collect { case namedTask: NamedTask[_] => namedTask.ctx.enclosingCls } + .collect { case namedTask: NamedTask[?] => namedTask.ctx.enclosingCls } .map(cls => cls -> resolveTransitiveParents(cls).toVector) .toMap @@ -277,22 +277,23 @@ private[mill] trait EvaluatorCore extends GroupEvaluator { .flatMap(_._2) .toSet - val allTransitiveClassMethods = allTransitiveClasses - .map { cls => - val cMangledName = cls.getName.replace('.', '$') - cls -> cls.getDeclaredMethods - .flatMap { m => - Seq( - m.getName -> m, - // Handle scenarios where private method names get mangled when they are - // not really JVM-private due to being accessed by Scala nested objects - // or classes https://github.com/scala/bug/issues/9306 - m.getName.stripPrefix(cMangledName + "$$") -> m, - m.getName.stripPrefix(cMangledName + "$") -> m - ) - }.toMap - } - .toMap + val allTransitiveClassMethods: Map[Class[?], Map[String, java.lang.reflect.Method]] = + allTransitiveClasses + .map { cls => + val cMangledName = cls.getName.replace('.', '$') + cls -> cls.getDeclaredMethods + .flatMap { m => + Seq( + m.getName -> m, + // Handle scenarios where private method names get mangled when they are + // not really JVM-private due to being accessed by Scala nested objects + // or classes https://github.com/scala/bug/issues/9306 + m.getName.stripPrefix(cMangledName + "$$") -> m, + m.getName.stripPrefix(cMangledName + "$") -> m + ) + }.toMap + } + .toMap (classToTransitiveClasses, allTransitiveClassMethods) } diff --git a/main/eval/src/mill/eval/GroupEvaluator.scala b/main/eval/src/mill/eval/GroupEvaluator.scala index 676505ecf985..a5db8328364c 100644 --- a/main/eval/src/mill/eval/GroupEvaluator.scala +++ b/main/eval/src/mill/eval/GroupEvaluator.scala @@ -383,7 +383,7 @@ private[mill] trait GroupEvaluator { .task .writerOpt .map { w => - upickle.default.writeJs(v.value)(w.asInstanceOf[upickle.default.Writer[Any]]) + upickle.default.writeJs(v.value)(using w.asInstanceOf[upickle.default.Writer[Any]]) } .orElse { labelled.task.asWorker.map { w => @@ -438,7 +438,7 @@ private[mill] trait GroupEvaluator { _ <- Option.when(cached.inputsHash == inputsHash)(()) reader <- labelled.task.readWriterOpt parsed <- - try Some(upickle.default.read(cached.value)(reader)) + try Some(upickle.default.read(cached.value)(using reader)) catch { case e: PathRef.PathRefValidationException => logger.debug( diff --git a/main/eval/test/src/mill/eval/EvaluationTests.scala b/main/eval/test/src/mill/eval/EvaluationTests.scala index ea0462c123f6..021d57906637 100644 --- a/main/eval/test/src/mill/eval/EvaluationTests.scala +++ b/main/eval/test/src/mill/eval/EvaluationTests.scala @@ -1,6 +1,6 @@ package mill.eval -import mill.util.TestUtil.{Test, test} +import mill.util.TestUtil.Test import mill.define.{TargetImpl, Task} import mill.T import mill.util.{TestGraphs, TestUtil} @@ -61,9 +61,10 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { object graphs extends TestGraphs() import graphs._ import TestGraphs._ - utest.test("evaluateSingle") { + import utest._ + test("evaluateSingle") { - utest.test("singleton") { + test("singleton") { import singleton._ val check = new Checker(singleton) // First time the target is evaluated @@ -73,7 +74,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { // After incrementing the counter, it forces re-evaluation check(single, expValue = 1, expEvaled = Agg(single)) } - utest.test("backtickIdentifiers") { + test("backtickIdentifiers") { import graphs.bactickIdentifiers._ val check = new Checker(bactickIdentifiers) @@ -85,7 +86,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { `up-target`.counter += 1 check(`a-down-target`, expValue = 2, expEvaled = Agg(`up-target`, `a-down-target`)) } - utest.test("pair") { + test("pair") { import pair._ val check = new Checker(pair) check(down, expValue = 0, expEvaled = Agg(up, down)) @@ -96,7 +97,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { up.counter += 1 check(down, expValue = 2, expEvaled = Agg(up, down)) } - utest.test("anonTriple") { + test("anonTriple") { import anonTriple._ val check = new Checker(anonTriple) val middle = down.inputs(0) @@ -112,7 +113,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { check(down, expValue = 3, expEvaled = Agg(middle, down)) } - utest.test("diamond") { + test("diamond") { import diamond._ val check = new Checker(diamond) check(down, expValue = 0, expEvaled = Agg(up, left, right, down)) @@ -130,7 +131,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { right.counter += 1 check(down, expValue = 5, expEvaled = Agg(right, down)) } - utest.test("anonDiamond") { + test("anonDiamond") { import anonDiamond._ val check = new Checker(anonDiamond) val left = down.inputs(0).asInstanceOf[TestUtil.Test] @@ -151,7 +152,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { check(down, expValue = 5, expEvaled = Agg(left, right, down)) } - utest.test("bigSingleTerminal") { + test("bigSingleTerminal") { import bigSingleTerminal._ val check = new Checker(bigSingleTerminal) @@ -170,8 +171,8 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { } } - utest.test("evaluateMixed") { - utest.test("separateGroups") { + test("evaluateMixed") { + test("separateGroups") { // Make sure that `left` and `right` are able to recompute separately, // even though one depends on the other @@ -189,7 +190,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { assert(filtered3 == Agg(change, right)) } - utest.test("triangleTask") { + test("triangleTask") { import triangleTask._ val checker = new Checker(triangleTask) @@ -197,7 +198,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { checker(left, 1, Agg(), extraEvaled = -1) } - utest.test("multiTerminalGroup") { + test("multiTerminalGroup") { import multiTerminalGroup._ val checker = new Checker(multiTerminalGroup) @@ -205,7 +206,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { checker(left, 1, Agg(left), extraEvaled = -1) } - utest.test("multiTerminalBoundary") { + test("multiTerminalBoundary") { import multiTerminalBoundary._ @@ -214,7 +215,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { checker(task2, 4, Agg(), extraEvaled = -1, secondRunNoOp = false) } - utest.test("overrideSuperTask") { + test("overrideSuperTask") { // Make sure you can override targets, call their supers, and have the // overridden target be allocated a spot within the overridden/ folder of // the main publicly-available target @@ -234,7 +235,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { !overridden.contains("object") ) } - utest.test("overrideSuperCommand") { + test("overrideSuperCommand") { // Make sure you can override commands, call their supers, and have the // overridden command be allocated a spot within the super/ folder of // the main publicly-available command @@ -261,7 +262,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { !overridden.contains("object1") ) } - utest.test("nullTasks") { + test("nullTasks") { import nullTasks._ val checker = new Checker(nullTasks) checker(nullTarget1, null, Agg(nullTarget1), extraEvaled = -1) @@ -288,7 +289,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { checker(nc4, null, Agg(nc4), extraEvaled = -1, secondRunNoOp = false) } - utest.test("tasksAreUncached") { + test("tasksAreUncached") { // Make sure the tasks `left` and `middle` re-compute every time, while // the target `right` does not // @@ -301,7 +302,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { var leftCount = 0 var rightCount = 0 var middleCount = 0 - def up = Task { test.anon() } + def up = Task { TestUtil.test.anon() } def left = Task.Anon { leftCount += 1; up() + 1 } def middle = Task.Anon { middleCount += 1; 100 } def right = Task { rightCount += 1; 10000 } @@ -352,7 +353,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { assert(leftCount == 4, middleCount == 4, rightCount == 1) } } - utest.test("stackableOverrides") { + test("stackableOverrides") { // Make sure you can override commands, call their supers, and have the // overridden command be allocated a spot within the super/ folder of // the main publicly-available command @@ -376,7 +377,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { ) assert(os.read(checker.evaluator.outPath / "m/f.json").contains(" 6,")) } - utest.test("stackableOverrides2") { + test("stackableOverrides2") { // When the supers have the same name, qualify them until they are distinct import StackableOverrides2._ @@ -398,7 +399,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { ) assert(os.read(checker.evaluator.outPath / "m/f.json").contains(" 6,")) } - utest.test("stackableOverrides3") { + test("stackableOverrides3") { // When the supers have the same name, qualify them until they are distinct import StackableOverrides3._ @@ -420,7 +421,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { ) assert(os.read(checker.evaluator.outPath / "m/f.json").contains(" 6,")) } - utest.test("privateTasksInMixedTraits") { + test("privateTasksInMixedTraits") { // Make sure we can have private cached targets in different trait with the same name, // and caching still works when these traits are mixed together import PrivateTasksInMixedTraits._ diff --git a/main/init/src/mill/init/InitModule.scala b/main/init/src/mill/init/InitModule.scala index 76b054427675..87bfcd41a04e 100644 --- a/main/init/src/mill/init/InitModule.scala +++ b/main/init/src/mill/init/InitModule.scala @@ -57,7 +57,7 @@ trait InitModule extends Module { val extractedPath = T.dest / extractedDirName val conflicting = for { p <- os.walk(extractedPath) - val rel = p.relativeTo(extractedPath) + rel = p.relativeTo(extractedPath) if os.exists(T.workspace / rel) } yield rel @@ -97,7 +97,8 @@ trait InitModule extends Module { private def usingExamples[T](fun: Seq[(ExampleId, ExampleUrl)] => T): Try[T] = Using(getClass.getClassLoader.getResourceAsStream("exampleList.txt")) { exampleList => val reader = upickle.default.reader[Seq[(ExampleId, ExampleUrl)]] - val exampleNames: Seq[(ExampleId, ExampleUrl)] = upickle.default.read(exampleList)(reader) + val exampleNames: Seq[(ExampleId, ExampleUrl)] = + upickle.default.read(exampleList)(using reader) fun(exampleNames) } } diff --git a/main/package.mill b/main/package.mill index 1ef11936329f..083d84bce055 100644 --- a/main/package.mill +++ b/main/package.mill @@ -5,6 +5,7 @@ import mill.scalalib._ import mill.contrib.buildinfo.BuildInfo import mill.T import mill.define.Cross +import mill.scalalib.api.ZincWorkerUtil object `package` extends RootModule with build.MillStableScalaModule with BuildInfo { @@ -19,12 +20,19 @@ object `package` extends RootModule with build.MillStableScalaModule with BuildI ivy"guru.nidi:graphviz-java-min-deps:0.18.1" ) - def compileIvyDeps = Agg(build.Deps.scalaReflect(scalaVersion())) + def compileIvyDeps = T { + if (ZincWorkerUtil.isScala3(scalaVersion())) Agg.empty else Agg(build.Deps.scalaReflect(scalaVersion())) + } def buildInfoPackageName = "mill.main" def buildInfoMembers = Seq( BuildInfo.Value("scalaVersion", scalaVersion(), "Scala version used to compile mill core."), + BuildInfo.Value( + "workerScalaVersion213", + build.Deps.scala2Version, + "Scala 2.13 version used by some workers." + ), BuildInfo.Value( "workerScalaVersion212", build.Deps.workerScalaVersion212, @@ -97,9 +105,15 @@ object `package` extends RootModule with build.MillStableScalaModule with BuildI object define extends build.MillStableScalaModule { def moduleDeps = Seq(api, util) - def compileIvyDeps = Agg(build.Deps.scalaReflect(scalaVersion())) + def compileIvyDeps = T { + if (ZincWorkerUtil.isScala3(scalaVersion())) Agg(build.Deps.scalaCompiler(scalaVersion())) + else Agg(build.Deps.scalaReflect(scalaVersion())) + } def ivyDeps = Agg( build.Deps.millModuledefs, + // TODO: somewhere sourcecode is included transitively, + // but we need the latest version to bring the macro improvements. + build.Deps.sourcecode, // Necessary so we can share the JNA classes throughout the build process build.Deps.jna, build.Deps.jnaPlatform, diff --git a/main/resolve/src/mill/resolve/ExpandBraces.scala b/main/resolve/src/mill/resolve/ExpandBraces.scala index fe68892a7498..fdef17c5a1f1 100644 --- a/main/resolve/src/mill/resolve/ExpandBraces.scala +++ b/main/resolve/src/mill/resolve/ExpandBraces.scala @@ -10,7 +10,7 @@ private object ExpandBraces { case class Expand(values: List[List[Fragment]]) extends Fragment } - def expandRec(frags: List[Fragment]): List[List[String]] = frags match { + private[ExpandBraces] def expandRec(frags: List[Fragment]): List[List[String]] = frags match { case Nil => List(List()) case head :: tail => val tailStrings = expandRec(tail) @@ -30,7 +30,7 @@ private object ExpandBraces { } def expandBraces(selectorString: String): Either[String, Seq[String]] = { - parse(selectorString, parser(_)) match { + parse(selectorString, parser(using _)) match { case f: Parsed.Failure => Left(s"Parsing exception ${f.msg}") case Parsed.Success(fragmentLists, _) => Right(expandRec(fragmentLists.toList).map(_.mkString)) diff --git a/main/resolve/src/mill/resolve/ParseArgs.scala b/main/resolve/src/mill/resolve/ParseArgs.scala index 36d6a8545b3b..ae32b9089bf4 100644 --- a/main/resolve/src/mill/resolve/ParseArgs.scala +++ b/main/resolve/src/mill/resolve/ParseArgs.scala @@ -88,7 +88,7 @@ object ParseArgs { def extractSegments(selectorString: String) : Either[String, (Option[Segments], Option[Segments])] = - parse(selectorString, selector(_)) match { + parse(selectorString, selector(using _)) match { case f: Parsed.Failure => Left(s"Parsing exception ${f.msg}") case Parsed.Success(selector, _) => Right(selector) } diff --git a/main/resolve/src/mill/resolve/ResolveNotFoundHandler.scala b/main/resolve/src/mill/resolve/ResolveNotFoundHandler.scala index 792cb9202280..7b6551ed1fa9 100644 --- a/main/resolve/src/mill/resolve/ResolveNotFoundHandler.scala +++ b/main/resolve/src/mill/resolve/ResolveNotFoundHandler.scala @@ -42,7 +42,7 @@ private object ResolveNotFoundHandler { val search = revSelectorsSoFar.render val lastSearchOpt = for { - Segment.Label(s) <- Option(lastSegment) + case Segment.Label(s) <- Option(lastSegment) if s != "_" && s != "__" possibility <- findMostSimilar(s, allPossibleNames) } yield "__." + possibility @@ -71,13 +71,13 @@ private object ResolveNotFoundHandler { } def errorMsgLabel( - given: String, + `given`: String, possibleMembers: Set[String], prefixSegments: Segments, fullSegments: Segments, allPossibleNames: Set[String] ): String = { - val suggestion = findMostSimilar(given, possibleMembers) match { + val suggestion = findMostSimilar(`given`, possibleMembers) match { case None => hintListLabel(prefixSegments, fullSegments.value.last, allPossibleNames) case Some(similar) => " Did you mean " + diff --git a/main/server/src/mill/main/server/Server.scala b/main/server/src/mill/main/server/Server.scala index 0852c4afef3a..9b24dab9d0d4 100644 --- a/main/server/src/mill/main/server/Server.scala +++ b/main/server/src/mill/main/server/Server.scala @@ -56,7 +56,8 @@ abstract class Server[T]( serverLog("handling run") try handleRun(sock, initialSystemProperties) catch { - case e: Throwable => serverLog(e + "\n" + e.getStackTrace.mkString("\n")) + case e: Throwable => + serverLog(e.toString + "\n" + e.getStackTrace.mkString("\n")) } finally sock.close(); true } diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index df6ddd5a2398..1771b96608b9 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -438,7 +438,7 @@ trait MainModule extends BaseModule0 { for { workerSegments <- evaluator.workerCache.keys.toList if allSegments.exists(workerSegments.startsWith) - (_, Val(closeable: AutoCloseable)) <- + case (_, Val(closeable: AutoCloseable)) <- evaluator.mutableWorkerCache.remove(workerSegments) } { closeable.close() @@ -481,7 +481,7 @@ trait MainModule extends BaseModule0 { */ def shutdown(): Command[Unit] = Task.Command(exclusive = true) { Target.log.info("Shutting down Mill server...") - Target.ctx.systemExit(0) + Target.ctx().systemExit(0) () } diff --git a/main/util/src/mill/util/PrefixLogger.scala b/main/util/src/mill/util/PrefixLogger.scala index 68cd02e7321e..47e8484bd822 100644 --- a/main/util/src/mill/util/PrefixLogger.scala +++ b/main/util/src/mill/util/PrefixLogger.scala @@ -67,11 +67,11 @@ class PrefixLogger( override def info(s: String): Unit = { reportKey(logPrefixKey) - logger0.info(infoColor(linePrefix) + s) + logger0.info("" + infoColor(linePrefix) + s) } override def error(s: String): Unit = { reportKey(logPrefixKey) - logger0.error(infoColor(linePrefix) + s) + logger0.error("" + infoColor(linePrefix) + s) } override def ticker(s: String): Unit = setPromptDetail(logPrefixKey, s) override def setPromptDetail(key: Seq[String], s: String): Unit = logger0.setPromptDetail(key, s) @@ -90,7 +90,7 @@ class PrefixLogger( override def debug(s: String): Unit = { if (debugEnabled) reportKey(logPrefixKey) - logger0.debug(infoColor(linePrefix) + s) + logger0.debug("" + infoColor(linePrefix) + s) } override def debugEnabled: Boolean = logger0.debugEnabled From d87ad0c6bb3df013b821acf066d21c6f1c343599 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 03:08:24 +0200 Subject: [PATCH 03/13] . --- bsp/src/mill/bsp/BSP.scala | 2 +- idea/src/mill/idea/GenIdea.scala | 1 + main/src/mill/main/TokenReaders.scala | 1 + .../linenumbers/resources/scalac-plugin.xml | 4 - .../linenumbers/LineNumberCorrector.scala | 65 --- .../mill/linenumbers/LineNumberPlugin.scala | 44 -- .../src/mill/scalajslib/ScalaJSModule.scala | 4 +- .../mill/scalajslib/CompileLinkTests.scala | 9 +- .../mill/scalajslib/EsModuleRemapTests.scala | 10 +- .../scalajslib/FullOptESModuleTests.scala | 5 +- .../mill/scalajslib/MultiModuleTests.scala | 5 +- .../mill/scalajslib/NodeJSConfigTests.scala | 7 +- .../mill/scalajslib/OutputPatternsTests.scala | 5 +- .../scalajslib/ScalaTestsErrorTests.scala | 5 +- .../scalajslib/SmallModulesForTests.scala | 5 +- .../src/mill/scalajslib/SourceMapTests.scala | 5 +- .../scalajslib/TopLevelExportsTests.scala | 5 +- .../src/mill/scalalib/CrossSbtModule.scala | 1 - scalalib/src/mill/scalalib/Dep.scala | 8 +- scalalib/src/mill/scalalib/JavaModule.scala | 18 +- .../src/mill/scalalib/PublishModule.scala | 6 +- scalalib/src/mill/scalalib/ScalaModule.scala | 5 +- .../src/mill/scalalib/ZincWorkerModule.scala | 5 +- .../dependency/updates/UpdatesFinder.scala | 2 +- .../dependency/versions/VersionParser.scala | 2 +- .../mill/scalalib/giter8/Giter8Module.scala | 21 +- .../mill/scalalib/publish/VersionScheme.scala | 3 +- .../mill/scalalib/worker/ZincWorkerImpl.scala | 411 ++++++++++++++++-- .../mill/scalanativelib/CompileRunTests.scala | 2 +- .../mill/scalanativelib/ExclusionsTests.scala | 1 + .../mill/scalanativelib/FeaturesTests.scala | 1 + .../scalanativelib/ScalaTestsErrorTests.scala | 5 +- .../src/mill/testkit/IntegrationTester.scala | 2 +- testkit/src/mill/testkit/UnitTester.scala | 2 +- 34 files changed, 494 insertions(+), 183 deletions(-) delete mode 100644 runner/linenumbers/resources/scalac-plugin.xml delete mode 100644 runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala delete mode 100644 runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala diff --git a/bsp/src/mill/bsp/BSP.scala b/bsp/src/mill/bsp/BSP.scala index 4eea72bc9b33..285383bb8758 100644 --- a/bsp/src/mill/bsp/BSP.scala +++ b/bsp/src/mill/bsp/BSP.scala @@ -1,7 +1,7 @@ package mill.bsp import mill.api.{Ctx, PathRef} -import mill.{Agg, T, Task} +import mill.{Agg, T, Task, given} import mill.define.{Command, Discover, ExternalModule} import mill.main.BuildInfo import mill.eval.Evaluator diff --git a/idea/src/mill/idea/GenIdea.scala b/idea/src/mill/idea/GenIdea.scala index 31b7fab6ebe2..66c3f76224db 100644 --- a/idea/src/mill/idea/GenIdea.scala +++ b/idea/src/mill/idea/GenIdea.scala @@ -1,5 +1,6 @@ package mill.idea +import mill.given import mill.Task import mill.api.Result import mill.define.{Command, Discover, ExternalModule} diff --git a/main/src/mill/main/TokenReaders.scala b/main/src/mill/main/TokenReaders.scala index 60c1b03e5d03..44374818aba2 100644 --- a/main/src/mill/main/TokenReaders.scala +++ b/main/src/mill/main/TokenReaders.scala @@ -69,4 +69,5 @@ trait TokenReaders0 { case t: TokensReader.Leftover[_, _] => new LeftoverTaskTokenReader[T](t) } + def given = () // dummy for scala 2/3 compat } diff --git a/runner/linenumbers/resources/scalac-plugin.xml b/runner/linenumbers/resources/scalac-plugin.xml deleted file mode 100644 index 7a27d92f3f79..000000000000 --- a/runner/linenumbers/resources/scalac-plugin.xml +++ /dev/null @@ -1,4 +0,0 @@ - - mill-linenumber-plugin - mill.linenumbers.LineNumberPlugin - \ No newline at end of file diff --git a/runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala b/runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala deleted file mode 100644 index 74fa588f9e3c..000000000000 --- a/runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala +++ /dev/null @@ -1,65 +0,0 @@ -package mill.linenumbers - -import scala.tools.nsc.Global - -object LineNumberCorrector { - def apply( - g: Global, - lines: Seq[String], - adjustedFile: String - )(unit: g.CompilationUnit): g.Tree = { - - val userCodeStartMarker = "//MILL_USER_CODE_START_MARKER" - - import scala.reflect.internal.util._ - - val markerLine = lines.indexWhere(_.startsWith(userCodeStartMarker)) - - val topWrapperLen = lines.take(markerLine + 1).map(_.length).sum - - val trimmedSource = new BatchSourceFile( - new scala.reflect.io.PlainFile(adjustedFile), - g.currentSource.content.drop(topWrapperLen) - ) - - import scala.reflect.internal.util._ - object Transformer extends g.Transformer { - override def transform(tree: g.Tree) = { - val transformedTree = super.transform(tree) - // The `start` and `end` values in transparent/range positions are left - // untouched, because of some aggressive validation in scalac that checks - // that trees are not overlapping, and shifting these values here - // violates the invariant (which breaks Ammonite, potentially because - // of multi-stage). - // Moreover, we rely only on the "point" value (for error reporting). - // The ticket https://github.com/scala/scala-dev/issues/390 tracks down - // relaxing the aggressive validation. - val newPos = tree.pos match { - case s: TransparentPosition if s.start > topWrapperLen => - new TransparentPosition( - trimmedSource, - s.start - topWrapperLen, - s.point - topWrapperLen, - s.end - topWrapperLen - ) - case s: RangePosition if s.start > topWrapperLen => - new RangePosition( - trimmedSource, - s.start - topWrapperLen, - s.point - topWrapperLen, - s.end - topWrapperLen - ) - case s: OffsetPosition if s.start > topWrapperLen => - new OffsetPosition(trimmedSource, s.point - topWrapperLen) - case s => s - - } - transformedTree.pos = newPos - - transformedTree - } - } - Transformer.transform(unit.body) - } - -} diff --git a/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala b/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala deleted file mode 100644 index b8f0aeee877a..000000000000 --- a/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala +++ /dev/null @@ -1,44 +0,0 @@ -package mill.linenumbers - -import mill.main.client.CodeGenConstants.buildFileExtensions -import scala.tools.nsc._ -import scala.tools.nsc.plugins.{Plugin, PluginComponent} - -/** - * Used to capture the names in scope after every execution, reporting them - * to the `output` function. Needs to be a compiler plugin so we can hook in - * immediately after the `typer` - */ -class LineNumberPlugin(val global: Global) extends Plugin { - override def init(options: List[String], error: String => Unit): Boolean = true - val name: String = "mill-linenumber-plugin" - val description = "Adjusts line numbers in the user-provided script to compensate for wrapping" - val components: List[PluginComponent] = List( - new PluginComponent { - val global = LineNumberPlugin.this.global - val runsAfter = List("parser") - val phaseName = "FixLineNumbers" - def newPhase(prev: Phase): Phase = new global.GlobalPhase(prev) { - def name = phaseName - def apply(unit: global.CompilationUnit): Unit = { - LineNumberPlugin.apply(global)(unit) - } - } - } - ) -} - -object LineNumberPlugin { - def apply(g: Global)(unit: g.CompilationUnit): Unit = { - if (buildFileExtensions.exists(ex => g.currentSource.file.name.endsWith(s".$ex"))) { - - val str = new String(g.currentSource.content) - val lines = str.linesWithSeparators.toVector - val adjustedFile = lines - .collectFirst { case s"//MILL_ORIGINAL_FILE_PATH=$rest" => rest.trim } - .getOrElse(sys.error(g.currentSource.path)) - - unit.body = LineNumberCorrector(g, lines, adjustedFile)(unit) - } - } -} diff --git a/scalajslib/src/mill/scalajslib/ScalaJSModule.scala b/scalajslib/src/mill/scalajslib/ScalaJSModule.scala index 1d88914ded0b..10b412d17415 100644 --- a/scalajslib/src/mill/scalajslib/ScalaJSModule.scala +++ b/scalajslib/src/mill/scalajslib/ScalaJSModule.scala @@ -76,7 +76,7 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => def scalaJSLinkerClasspath: T[Loose.Agg[PathRef]] = Task { val commonDeps = Seq( - ivy"org.scala-js::scalajs-sbt-test-adapter:${scalaJSVersion()}" + ivy"org.scala-js:scalajs-sbt-test-adapter_2.13:${scalaJSVersion()}" ) val scalajsImportMapDeps = scalaJSVersion() match { case s"1.$n.$_" if n.toIntOption.exists(_ >= 16) && scalaJSImportMap().nonEmpty => @@ -92,7 +92,7 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => ) case "1" => Seq( - ivy"org.scala-js::scalajs-linker:${scalaJSVersion()}" + ivy"org.scala-js:scalajs-linker_2.13:${scalaJSVersion()}" ) ++ scalaJSJsEnvIvyDeps() } // we need to use the scala-library of the currently running mill diff --git a/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala b/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala index efd9e0ac40bb..43822fbe8702 100644 --- a/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala +++ b/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala @@ -44,7 +44,7 @@ object CompileLinkTests extends TestSuite { ) object `test-utest` extends ScalaJSTests with TestModule.Utest { - override def sources = Task.Sources { millSourcePath / "src/utest" } + override def sources = Task.Sources { this.millSourcePath / "src/utest" } val utestVersion = if (ZincWorkerUtil.isScala3(crossScalaVersion)) "0.7.7" else "0.7.5" override def ivyDeps = Agg( ivy"com.lihaoyi::utest::$utestVersion" @@ -52,7 +52,7 @@ object CompileLinkTests extends TestSuite { } object `test-scalatest` extends ScalaJSTests with TestModule.ScalaTest { - override def sources = Task.Sources { millSourcePath / "src/scalatest" } + override def sources = Task.Sources { this.millSourcePath / "src/scalatest" } override def ivyDeps = Agg( ivy"org.scalatest::scalatest::3.1.2" ) @@ -68,7 +68,10 @@ object CompileLinkTests extends TestSuite { object test extends ScalaJSTests with TestModule.Utest } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "hello-js-world" diff --git a/scalajslib/test/src/mill/scalajslib/EsModuleRemapTests.scala b/scalajslib/test/src/mill/scalajslib/EsModuleRemapTests.scala index 025fe0106791..488c051082ee 100644 --- a/scalajslib/test/src/mill/scalajslib/EsModuleRemapTests.scala +++ b/scalajslib/test/src/mill/scalajslib/EsModuleRemapTests.scala @@ -25,7 +25,10 @@ object EsModuleRemapTests extends TestSuite { ESModuleImportMapping.Prefix("@stdlib/linspace", remapTo) ) - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } object OldJsModule extends TestBaseModule with ScalaJSModule { @@ -38,7 +41,10 @@ object EsModuleRemapTests extends TestSuite { ESModuleImportMapping.Prefix("@stdlib/linspace", remapTo) ) - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "esModuleRemap" diff --git a/scalajslib/test/src/mill/scalajslib/FullOptESModuleTests.scala b/scalajslib/test/src/mill/scalajslib/FullOptESModuleTests.scala index 9da8030876fe..417b8a34c34a 100644 --- a/scalajslib/test/src/mill/scalajslib/FullOptESModuleTests.scala +++ b/scalajslib/test/src/mill/scalajslib/FullOptESModuleTests.scala @@ -16,7 +16,10 @@ object FullOptESModuleTests extends TestSuite { override def moduleKind = ModuleKind.ESModule } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "hello-js-world" diff --git a/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala b/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala index 7df52a447d1c..4ca8c7d6543f 100644 --- a/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala +++ b/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala @@ -29,7 +29,10 @@ object MultiModuleTests extends TestSuite { override def millSourcePath = MultiModule.millSourcePath / "shared" } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val evaluator = UnitTester(MultiModule, sourcePath) diff --git a/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala b/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala index 730866725fa1..3c6b3dca10c1 100644 --- a/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala +++ b/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala @@ -43,7 +43,7 @@ object NodeJSConfigTests extends TestSuite { override def jsEnvConfig = Task { JsEnvConfig.NodeJs(args = nodeArgs) } object `test-utest` extends ScalaJSTests with TestModule.Utest { - override def sources = Task.Sources { millSourcePath / "src/utest" } + override def sources = Task.Sources { this.millSourcePath / "src/utest" } override def ivyDeps = Agg( ivy"com.lihaoyi::utest::$utestVersion" ) @@ -51,7 +51,10 @@ object NodeJSConfigTests extends TestSuite { } } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "hello-js-world" diff --git a/scalajslib/test/src/mill/scalajslib/OutputPatternsTests.scala b/scalajslib/test/src/mill/scalajslib/OutputPatternsTests.scala index 34dbb7f9f6e0..4e4aaca417c9 100644 --- a/scalajslib/test/src/mill/scalajslib/OutputPatternsTests.scala +++ b/scalajslib/test/src/mill/scalajslib/OutputPatternsTests.scala @@ -18,7 +18,10 @@ object OutputPatternsTests extends TestSuite { override def scalaJSOutputPatterns = OutputPatterns.fromJSFile("%s.mjs") } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "hello-js-world" diff --git a/scalajslib/test/src/mill/scalajslib/ScalaTestsErrorTests.scala b/scalajslib/test/src/mill/scalajslib/ScalaTestsErrorTests.scala index 97d1d3e84e61..6b9f5165af47 100644 --- a/scalajslib/test/src/mill/scalajslib/ScalaTestsErrorTests.scala +++ b/scalajslib/test/src/mill/scalajslib/ScalaTestsErrorTests.scala @@ -16,7 +16,10 @@ object ScalaTestsErrorTests extends TestSuite { override def hierarchyChecks(): Unit = {} } } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } def tests: Tests = Tests { diff --git a/scalajslib/test/src/mill/scalajslib/SmallModulesForTests.scala b/scalajslib/test/src/mill/scalajslib/SmallModulesForTests.scala index 25c5c7150b25..07a155406f4a 100644 --- a/scalajslib/test/src/mill/scalajslib/SmallModulesForTests.scala +++ b/scalajslib/test/src/mill/scalajslib/SmallModulesForTests.scala @@ -15,7 +15,10 @@ object SmallModulesForTests extends TestSuite { override def moduleKind = ModuleKind.ESModule override def moduleSplitStyle = ModuleSplitStyle.SmallModulesFor(List("app")) - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "small-modules-for" diff --git a/scalajslib/test/src/mill/scalajslib/SourceMapTests.scala b/scalajslib/test/src/mill/scalajslib/SourceMapTests.scala index a52ba7edaa3f..b83b11552ba8 100644 --- a/scalajslib/test/src/mill/scalajslib/SourceMapTests.scala +++ b/scalajslib/test/src/mill/scalajslib/SourceMapTests.scala @@ -15,7 +15,10 @@ object SourceMapTests extends TestSuite { override def scalaJSSourceMap = false } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "hello-js-world" diff --git a/scalajslib/test/src/mill/scalajslib/TopLevelExportsTests.scala b/scalajslib/test/src/mill/scalajslib/TopLevelExportsTests.scala index 6ea7bbaf780e..c3eba073ce87 100644 --- a/scalajslib/test/src/mill/scalajslib/TopLevelExportsTests.scala +++ b/scalajslib/test/src/mill/scalajslib/TopLevelExportsTests.scala @@ -13,7 +13,10 @@ object TopLevelExportsTests extends TestSuite { sys.props.getOrElse("TEST_SCALAJS_VERSION", ???) // at least "1.8.0" override def moduleKind = ModuleKind.ESModule - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } val millSourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "top-level-exports" diff --git a/scalalib/src/mill/scalalib/CrossSbtModule.scala b/scalalib/src/mill/scalalib/CrossSbtModule.scala index 82434dc9d509..e80fce57571e 100644 --- a/scalalib/src/mill/scalalib/CrossSbtModule.scala +++ b/scalalib/src/mill/scalalib/CrossSbtModule.scala @@ -2,7 +2,6 @@ package mill.scalalib import mill.api.PathRef import mill.{T, Task} -import mill.scalalib.{CrossModuleBase, SbtModule} import scala.annotation.nowarn diff --git a/scalalib/src/mill/scalalib/Dep.scala b/scalalib/src/mill/scalalib/Dep.scala index b857131bc50f..0c1d41bf3515 100644 --- a/scalalib/src/mill/scalalib/Dep.scala +++ b/scalalib/src/mill/scalalib/Dep.scala @@ -172,11 +172,11 @@ object Dep { (dep: Dep) => unparse(dep) match { case Some(s) => ujson.Str(s) - case None => upickle.default.writeJs[Dep](dep)(rw0) + case None => upickle.default.writeJs[Dep](dep)(using rw0) }, { case s: ujson.Str => parse(s.value) - case v: ujson.Value => upickle.default.read[Dep](v)(rw0) + case v: ujson.Value => upickle.default.read[Dep](v)(using rw0) } ) @@ -279,7 +279,7 @@ object BoundDep { upickle.default.readwriter[ujson.Value].bimap[BoundDep]( bdep => { Dep.unparse(Dep(bdep.dep, CrossVersion.Constant("", false), bdep.force)) match { - case None => upickle.default.writeJs(bdep)(jsonify0) + case None => upickle.default.writeJs(bdep)(using jsonify0) case Some(s) => ujson.Str(s) } }, @@ -287,7 +287,7 @@ object BoundDep { case ujson.Str(s) => val dep = Dep.parse(s) BoundDep(dep.dep, dep.force) - case v => upickle.default.read[BoundDep](v)(jsonify0) + case v => upickle.default.read[BoundDep](v)(using jsonify0) } ) } diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala index 90d72e7b62bd..d2293189b8b1 100644 --- a/scalalib/src/mill/scalalib/JavaModule.scala +++ b/scalalib/src/mill/scalalib/JavaModule.scala @@ -1,11 +1,11 @@ package mill package scalalib -import coursier.Repository import coursier.core.Resolution import coursier.parse.JavaOrScalaModule import coursier.parse.ModuleParser import coursier.util.ModuleMatcher +import coursier.{Repository, Type} import mainargs.{Flag, arg} import mill.Agg import mill.api.{Ctx, JarManifest, MillException, PathRef, Result, internal} @@ -155,6 +155,12 @@ trait JavaModule */ def runIvyDeps: T[Agg[Dep]] = Task { Agg.empty[Dep] } + /** + * Default artifact types to fetch and put in the classpath. Add extra types + * here if you'd like fancy artifact extensions to be fetched. + */ + def artifactTypes: T[Set[Type]] = Task { coursier.core.Resolution.defaultTypes } + /** * Options to pass to the java compiler */ @@ -252,8 +258,10 @@ trait JavaModule else compileModuleDepsChecked val deps = (normalDeps ++ compileDeps).distinct val asString = - s"${if (recursive) "Recursive module" - else "Module"} dependencies of ${millModuleSegments.render}:\n\t${deps + s"${ + if (recursive) "Recursive module" + else "Module" + } dependencies of ${millModuleSegments.render}:\n\t${deps .map { dep => dep.millModuleSegments.render ++ (if (compileModuleDepsChecked.contains(dep) || !normalDeps.contains(dep)) " (compile)" @@ -551,7 +559,9 @@ trait JavaModule } def resolvedRunIvyDeps: T[Agg[PathRef]] = Task { - defaultResolver().resolveDeps(runIvyDeps().map(bindDependency()) ++ transitiveIvyDeps()) + defaultResolver().resolveDeps( + runIvyDeps().map(bindDependency()) ++ transitiveIvyDeps() + ) } /** diff --git a/scalalib/src/mill/scalalib/PublishModule.scala b/scalalib/src/mill/scalalib/PublishModule.scala index cefe014d11f1..eb3a7a22f01c 100644 --- a/scalalib/src/mill/scalalib/PublishModule.scala +++ b/scalalib/src/mill/scalalib/PublishModule.scala @@ -62,10 +62,11 @@ trait PublishModule extends JavaModule { outer => } def publishXmlDeps: Task[Agg[Dependency]] = Task.Anon { - val ivyPomDeps = (ivyDeps() ++ mandatoryIvyDeps()).map(resolvePublishDependency().apply(_)) + val ivyPomDeps = + (ivyDeps() ++ mandatoryIvyDeps()).map(resolvePublishDependency.apply().apply(_)) val compileIvyPomDeps = compileIvyDeps() - .map(resolvePublishDependency().apply(_)) + .map(resolvePublishDependency.apply().apply(_)) .filter(!ivyPomDeps.contains(_)) .map(_.copy(scope = Scope.Provided)) @@ -314,6 +315,7 @@ object PublishModule extends ExternalModule with TaskModule { (payload.map { case (p, f) => (p.path, f) }, meta) } object PublishData { + import mill.scalalib.publish.artifactFormat implicit def jsonify: upickle.default.ReadWriter[PublishData] = upickle.default.macroRW } diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index b2b839e55841..c91ef4add7b7 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -11,7 +11,10 @@ import mainargs.Flag import mill.scalalib.bsp.{BspBuildTarget, BspModule, ScalaBuildTarget, ScalaPlatform} import mill.scalalib.dependency.versions.{ValidVersion, Version} +// this import requires scala-reflect library to be on the classpath +// it was duplicated to scala3-compiler, but is that too powerful to add as a dependency? import scala.reflect.internal.util.ScalaClassLoader + import scala.util.Using /** @@ -56,7 +59,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase { outer => def scalaVersion: T[String] override def mapDependencies: Task[coursier.Dependency => coursier.Dependency] = Task.Anon { - super.mapDependencies().andThen { d: coursier.Dependency => + super.mapDependencies().andThen { (d: coursier.Dependency) => val artifacts = if (ZincWorkerUtil.isDotty(scalaVersion())) Set("dotty-library", "dotty-compiler") diff --git a/scalalib/src/mill/scalalib/ZincWorkerModule.scala b/scalalib/src/mill/scalalib/ZincWorkerModule.scala index 6861fdcacf08..eb2ebb6f6b1b 100644 --- a/scalalib/src/mill/scalalib/ZincWorkerModule.scala +++ b/scalalib/src/mill/scalalib/ZincWorkerModule.scala @@ -2,7 +2,6 @@ package mill.scalalib import coursier.Repository import mainargs.Flag -import mill.Agg import mill._ import mill.api.{Ctx, FixSizedCache, KeyedLockedCache, PathRef, Result} import mill.define.{ExternalModule, Discover} @@ -127,8 +126,8 @@ trait ZincWorkerModule extends mill.Module with OfflineSupportModule { self: Cou val bridgeJar = resolveDependencies( repositories, Seq(bridgeDep.bindDep("", "", "")), - useSources, - Some(overrideScalaLibrary(scalaVersion, scalaOrganization)) + sources = useSources, + mapDependencies = Some(overrideScalaLibrary(scalaVersion, scalaOrganization)) ).map(deps => ZincWorkerUtil.grepJar(deps, bridgeName, bridgeVersion, useSources) ) diff --git a/scalalib/src/mill/scalalib/dependency/updates/UpdatesFinder.scala b/scalalib/src/mill/scalalib/dependency/updates/UpdatesFinder.scala index 863019599d50..3ef00db20d06 100644 --- a/scalalib/src/mill/scalalib/dependency/updates/UpdatesFinder.scala +++ b/scalalib/src/mill/scalalib/dependency/updates/UpdatesFinder.scala @@ -74,5 +74,5 @@ private[dependency] object UpdatesFinder { case (_, _) => false } - private def isUpdate(current: Version) = current < _ + private def isUpdate(current: Version) = current < (_: Version) } diff --git a/scalalib/src/mill/scalalib/dependency/versions/VersionParser.scala b/scalalib/src/mill/scalalib/dependency/versions/VersionParser.scala index d4cb56c816fa..ef3757467b8e 100644 --- a/scalalib/src/mill/scalalib/dependency/versions/VersionParser.scala +++ b/scalalib/src/mill/scalalib/dependency/versions/VersionParser.scala @@ -27,5 +27,5 @@ private[dependency] object VersionParser { } def parse(text: String): Parsed[(Seq[Long], Seq[String], Seq[String])] = - fastparse.parse(text, versionParser(_)) + fastparse.parse(text, versionParser(using _)) } diff --git a/scalalib/src/mill/scalalib/giter8/Giter8Module.scala b/scalalib/src/mill/scalalib/giter8/Giter8Module.scala index c254512d2c8e..e7ab57573e2a 100644 --- a/scalalib/src/mill/scalalib/giter8/Giter8Module.scala +++ b/scalalib/src/mill/scalalib/giter8/Giter8Module.scala @@ -16,11 +16,22 @@ trait Giter8Module extends CoursierModule { def init(args: String*): Command[Unit] = Task.Command { T.log.info("Creating a new project...") - val giter8Dependencies = defaultResolver().resolveDeps { - val scalaBinVersion = ZincWorkerUtil.scalaBinaryVersion(BuildInfo.scalaVersion) - Loose.Agg(ivy"org.foundweekends.giter8:giter8_${scalaBinVersion}:0.14.0" - .bindDep("", "", "")) - } + + val giter8Dependencies = + try { + defaultResolver().resolveDeps { + val scalaBinVersion = { + val bv = ZincWorkerUtil.scalaBinaryVersion(BuildInfo.scalaVersion) + if (bv == "3") "2.13" else bv + } + Loose.Agg(ivy"org.foundweekends.giter8:giter8_${scalaBinVersion}:0.14.0" + .bindDep("", "", "")) + } + } catch { + case e: Exception => + T.log.error("Failed to resolve giter8 dependencies\n" + e.getMessage) + throw e + } Jvm.runSubprocess( "giter8.Giter8", diff --git a/scalalib/src/mill/scalalib/publish/VersionScheme.scala b/scalalib/src/mill/scalalib/publish/VersionScheme.scala index 8a53196c37a0..6fcba7457b53 100644 --- a/scalalib/src/mill/scalalib/publish/VersionScheme.scala +++ b/scalalib/src/mill/scalalib/publish/VersionScheme.scala @@ -33,5 +33,6 @@ object VersionScheme { case object Strict extends VersionScheme("strict") implicit val rwStrict: ReadWriter[Strict.type] = macroRW - implicit val rwVersionScheme: ReadWriter[VersionScheme.type] = macroRW + // edit @bishabosha: why was it `.type`, I assume it is meant to infer a sum type? + implicit val rwVersionScheme: ReadWriter[VersionScheme /*.type*/ ] = macroRW } diff --git a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala index 5b7c373992a2..7b53632afd8d 100644 --- a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala +++ b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala @@ -42,6 +42,7 @@ import xsbti.compile.{ import xsbti.{PathBasedFile, VirtualFile} import java.io.{File, PrintWriter} +import java.nio.charset.StandardCharsets import java.util.Optional import scala.annotation.tailrec import scala.collection.mutable @@ -144,7 +145,7 @@ class ZincWorkerImpl( compilerClasspath, scalacPluginClasspath, Seq() - ) { compilers: Compilers => + ) { (compilers: Compilers) => if (ZincWorkerUtil.isDotty(scalaVersion) || ZincWorkerUtil.isScala3Milestone(scalaVersion)) { // dotty 0.x and scala 3 milestones use the dotty-doc tool val dottydocClass = @@ -388,7 +389,7 @@ class ZincWorkerImpl( compilerClasspath = compilerClasspath, scalacPluginClasspath = scalacPluginClasspath, javacOptions = javacOptions - ) { compilers: Compilers => + ) { (compilers: Compilers) => compileInternal( upstreamCompileOutput = upstreamCompileOutput, sources = sources, @@ -495,6 +496,8 @@ class ZincWorkerImpl( auxiliaryClassFileExtensions: Seq[String], zincCache: os.SubPath = os.sub / "zinc" )(implicit ctx: ZincWorkerApi.Ctx): Result[CompilationResult] = { + import ZincWorkerImpl.{ForwardingReporter, TransformingReporter, PositionMapper} + os.makeDir.all(ctx.dest) val classesDir = @@ -525,30 +528,21 @@ class ZincWorkerImpl( val loggerId = Thread.currentThread().getId.toString val logger = SbtLoggerUtils.createLogger(loggerId, consoleAppender, zincLogLevel) - val newReporter = reporter match { - case None => new ManagedLoggedReporter(10, logger) with RecordingReporter - case Some(forwarder) => - new ManagedLoggedReporter(10, logger) with RecordingReporter { - - override def logError(problem: xsbti.Problem): Unit = { - forwarder.logError(new ZincProblem(problem)) - super.logError(problem) - } - - override def logWarning(problem: xsbti.Problem): Unit = { - forwarder.logWarning(new ZincProblem(problem)) - super.logWarning(problem) - } - - override def logInfo(problem: xsbti.Problem): Unit = { - forwarder.logInfo(new ZincProblem(problem)) - super.logInfo(problem) - } - - override def printSummary(): Unit = { - forwarder.printSummary() - super.printSummary() - } + def mkNewReporter(mapper: (xsbti.Position => xsbti.Position)) = reporter match { + case None => + new ManagedLoggedReporter(10, logger) with RecordingReporter + with TransformingReporter { + def color: Boolean = ctx.log.colored + def optPositionMapper = mapper + } + case Some(forwarder0) => + new ManagedLoggedReporter(10, logger) + with ForwardingReporter + with RecordingReporter + with TransformingReporter { + def forwarder = forwarder0 + def color: Boolean = ctx.log.colored + def optPositionMapper = mapper } } val analysisMap0 = upstreamCompileOutput.map(c => c.classes.path -> c.analysisFile).toMap @@ -581,6 +575,10 @@ class ZincWorkerImpl( auxiliaryClassFileExtensions.map(new AuxiliaryClassFileExtension(_)).toArray ) + val newReporter = mkNewReporter( + PositionMapper.create(virtualSources) + ) + val inputs = ic.inputs( classpath = classpath, sources = virtualSources, @@ -673,6 +671,367 @@ class ZincWorkerImpl( } object ZincWorkerImpl { + + /** + * TODO: copied from mill.scalalib.Assembly + */ + private object Streamable { + def bytes(is: java.io.InputStream): Array[Byte] = { + val out = new java.io.ByteArrayOutputStream + mill.api.IO.stream(is, out) + out.close() + out.toByteArray + } + } + + private def intValue(oi: java.util.Optional[Integer], default: Int): Int = { + if (oi.isPresent) oi.get().intValue() + else default + } + + private object PositionMapper { + import sbt.util.InterfaceUtil + + private val userCodeStartMarker = "//MILL_USER_CODE_START_MARKER" + private val splicedCodeStartMarker = "//MILL_SPLICED_CODE_START_MARKER" + private val splicedCodeEndMarker = "//MILL_SPLICED_CODE_END_MARKER" + + /** Transforms positions of problems if coming from a build file. */ + private def lookup(buildSources: Map[String, xsbti.Position => xsbti.Position])( + oldPos: xsbti.Position + ): xsbti.Position = { + val src = oldPos.sourcePath() + if (src.isPresent) { + buildSources.get(src.get()) match { + case Some(f) => f(oldPos) + case _ => oldPos + } + } else { + oldPos + } + } + + def create(sources: Array[VirtualFile]): (xsbti.Position => xsbti.Position) = { + val buildSources0 = { + def isBuild(vf: VirtualFile) = + mill.main.client.CodeGenConstants.buildFileExtensions.exists(ex => + vf.id().endsWith(s".$ex") + ) + + sources.collect({ + case vf if isBuild(vf) => + val str = new String(Streamable.bytes(vf.input()), StandardCharsets.UTF_8) + + val lines = str.linesWithSeparators.toVector + val adjustedFile = lines + .collectFirst { case s"//MILL_ORIGINAL_FILE_PATH=$rest" => rest.trim } + .getOrElse(sys.error(vf.id())) + + vf.id() -> remap(lines, adjustedFile) + }) + } + + if (buildSources0.nonEmpty) lookup(buildSources0.toMap) else null + } + + private def remap( + lines: Vector[String], + adjustedFile: String + ): xsbti.Position => xsbti.Position = { + val markerLine = lines.indexWhere(_.startsWith(userCodeStartMarker)) + val splicedMarkerStartLine = lines.indexWhere(_.startsWith(splicedCodeStartMarker)) + val splicedMarkerLine = lines.indexWhere(_.startsWith(splicedCodeEndMarker)) + val existsSplicedMarker = splicedMarkerStartLine >= 0 && splicedMarkerLine >= 0 + val splicedMarkerLineDiff = markerLine + (splicedMarkerLine - splicedMarkerStartLine + 1) + 1 + + val topWrapperLen = lines.take(markerLine + 1).map(_.length).sum + val splicedMarkerLen = + if (existsSplicedMarker) lines.take(splicedMarkerLine + 1).map(_.length).sum + else -1 + + val originPath = Some(adjustedFile) + val originFile = Some(java.nio.file.Paths.get(adjustedFile).toFile) + + def userCode(offset: java.util.Optional[Integer]): Boolean = + intValue(offset, -1) > topWrapperLen + + def postSplice(offset: Int): Boolean = + existsSplicedMarker && offset > splicedMarkerLen + + def inner(pos0: xsbti.Position): xsbti.Position = { + if (userCode(pos0.startOffset()) || userCode(pos0.offset())) { + val Array(line, offset, startOffset, endOffset, startLine, endLine) = + Array( + pos0.line(), + pos0.offset(), + pos0.startOffset(), + pos0.endOffset(), + pos0.startLine(), + pos0.endLine() + ) + .map(intValue(_, 1) - 1) + + val (baseLine, baseOffset) = + if (postSplice(startOffset) || postSplice(offset)) + (splicedMarkerLineDiff, splicedMarkerLen) + else + (markerLine, topWrapperLen) + + InterfaceUtil.position( + line0 = Some(line - baseLine), + content = pos0.lineContent(), + offset0 = Some(offset - baseOffset), + pointer0 = InterfaceUtil.jo2o(pos0.pointer()), + pointerSpace0 = InterfaceUtil.jo2o(pos0.pointerSpace()), + sourcePath0 = originPath, + sourceFile0 = originFile, + startOffset0 = Some(startOffset - baseOffset), + endOffset0 = Some(endOffset - baseOffset), + startLine0 = Some(startLine - baseLine), + startColumn0 = InterfaceUtil.jo2o(pos0.startColumn()), + endLine0 = Some(endLine - baseLine), + endColumn0 = InterfaceUtil.jo2o(pos0.endColumn()) + ) + } else { + pos0 + } + } + + inner + } + } + + private trait ForwardingReporter extends ManagedLoggedReporter { + def forwarder: CompileProblemReporter + override def logError(problem: xsbti.Problem): Unit = { + forwarder.logError(new ZincProblem(problem)) + super.logError(problem) + } + + override def logWarning(problem: xsbti.Problem): Unit = { + forwarder.logWarning(new ZincProblem(problem)) + super.logWarning(problem) + } + + override def logInfo(problem: xsbti.Problem): Unit = { + forwarder.logInfo(new ZincProblem(problem)) + super.logInfo(problem) + } + + override def printSummary(): Unit = { + forwarder.printSummary() + super.printSummary() + } + } + + private trait TransformingReporter extends xsbti.Reporter { + def color: Boolean + def optPositionMapper: (xsbti.Position => xsbti.Position) + + // Overriding this is necessary because for some reason the LoggedReporter doesn't transform positions + // of Actions and DiagnosticRelatedInformation + abstract override def log(problem0: xsbti.Problem): Unit = { + val localMapper = optPositionMapper + val problem = { + if (localMapper == null) problem0 + else TransformingReporter.transformProblem(color, problem0, localMapper) + } + super.log(problem) + } + } + + private object TransformingReporter { + + import scala.jdk.CollectionConverters._ + import sbt.util.InterfaceUtil + + /** implements a transformation that returns the same object if the mapper has no effect. */ + private def transformProblem( + color: Boolean, + problem0: xsbti.Problem, + mapper: xsbti.Position => xsbti.Position + ): xsbti.Problem = { + val pos0 = problem0.position() + val related0 = problem0.diagnosticRelatedInformation() + val actions0 = problem0.actions() + val pos = mapper(pos0) + val related = transformRelateds(related0, mapper) + val actions = transformActions(actions0, mapper) + val posIsNew = pos ne pos0 + if (posIsNew || (related ne related0) || (actions ne actions0)) { + val rendered = { + // if we transformed the position, then we must re-render the message + if (posIsNew) Some(dottyStyleMessage(color, problem0, pos)) + else InterfaceUtil.jo2o(problem0.rendered()) + } + InterfaceUtil.problem( + cat = problem0.category(), + pos = pos, + msg = problem0.message(), + sev = problem0.severity(), + rendered = rendered, + diagnosticCode = InterfaceUtil.jo2o(problem0.diagnosticCode()), + diagnosticRelatedInformation = anyToList(related), + actions = anyToList(actions) + ) + }else + problem0 + } + + private type JOrSList[T] = AnyRef + + private def anyToList[T](ts: JOrSList[T]): List[T] = ts match { + case ts: List[T] => ts + case ts: java.util.List[T] => ts.asScala.toList + } + + /** Render the message in the style of dotty */ + private def dottyStyleMessage( + color: Boolean, + problem0: xsbti.Problem, + pos: xsbti.Position + ): String = { + val base = problem0.message() + val severity = problem0.severity() + + def shade(msg: String) = + if (color) + severity match { + case xsbti.Severity.Error => Console.RED + msg + Console.RESET + case xsbti.Severity.Warn => Console.YELLOW + msg + Console.RESET + case xsbti.Severity.Info => Console.BLUE + msg + Console.RESET + } + else msg + + val normCode = { + problem0.diagnosticCode().filter(_.code() != "-1").map({ inner => + val prefix = s"[E${inner.code()}] " + inner.explanation().map(e => + s"$prefix$e: " + ).orElse(prefix) + }).orElse("") + } + + val optPath = InterfaceUtil.jo2o(pos.sourcePath()).map { path => + val line0 = intValue(pos.line(), -1) + val pointer0 = intValue(pos.pointer(), -1) + if (line0 >= 0 && pointer0 >= 0) + s"$path:$line0:${pointer0 + 1}" + else + path + } + + val normHeader = optPath.map(path => + s"${shade(s"-- $normCode$path")}\n" + ).getOrElse("") + + val optSnippet = { + val snip = pos.lineContent() + val space = pos.pointerSpace().orElse("") + val pointer = intValue(pos.pointer(), -99) + val endCol = intValue(pos.endColumn(), pointer + 1) + if (snip.nonEmpty && space.nonEmpty && pointer >= 0 && endCol >= 0) { + val arrowCount = math.max(1, math.min(endCol - pointer, snip.length - space.length)) + Some( + s"""$snip + |$space${"^" * arrowCount}""".stripMargin + ) + }else + None + } + + val content = optSnippet match { + case Some(snippet) => + val initial = { + s"""$snippet + |$base + |""".stripMargin + } + val snippetLine = intValue(pos.line(), -1) + if (snippetLine >= 0) { + // add margin with line number + val lines = initial.linesWithSeparators.toVector + val pre = snippetLine.toString + val rest0 = " " * pre.length + val rest = pre +: Vector.fill(lines.size - 1)(rest0) + rest.lazyZip(lines).map((pre, line) => shade(s"$pre │") + line).mkString + } else { + initial + } + case None => + base + } + + normHeader + content + } + + /** Implements a transformation that returns the same list if the mapper has no effect */ + private def transformActions( + actions0: java.util.List[xsbti.Action], + mapper: xsbti.Position => xsbti.Position + ): JOrSList[xsbti.Action] = { + if (actions0.iterator().asScala.exists(a => + a.edit().changes().iterator().asScala.exists(e => + mapper(e.position()) ne e.position() + ) + ) + ) { + actions0.iterator().asScala.map(transformAction(_, mapper)).toList + } else { + actions0 + } + } + + /** Implements a transformation that returns the same list if the mapper has no effect */ + private def transformRelateds( + related0: java.util.List[xsbti.DiagnosticRelatedInformation], + mapper: xsbti.Position => xsbti.Position + ): JOrSList[xsbti.DiagnosticRelatedInformation] = { + + if (related0.iterator().asScala.exists(r => mapper(r.position()) ne r.position())) + related0.iterator().asScala.map(transformRelated(_, mapper)).toList + else + related0 + } + + private def transformRelated( + related0: xsbti.DiagnosticRelatedInformation, + mapper: xsbti.Position => xsbti.Position + ): xsbti.DiagnosticRelatedInformation = { + InterfaceUtil.diagnosticRelatedInformation(mapper(related0.position()), related0.message()) + } + + private def transformAction( + action0: xsbti.Action, + mapper: xsbti.Position => xsbti.Position + ): xsbti.Action = { + InterfaceUtil.action( + title = action0.title(), + description = InterfaceUtil.jo2o(action0.description()), + edit = transformEdit(action0.edit(), mapper) + ) + } + + private def transformEdit( + edit0: xsbti.WorkspaceEdit, + mapper: xsbti.Position => xsbti.Position + ): xsbti.WorkspaceEdit = { + InterfaceUtil.workspaceEdit( + edit0.changes().iterator().asScala.map(transformTEdit(_, mapper)).toList + ) + } + + private def transformTEdit( + edit0: xsbti.TextEdit, + mapper: xsbti.Position => xsbti.Position + ): xsbti.TextEdit = { + InterfaceUtil.textEdit( + position = mapper(edit0.position()), + newText = edit0.newText() + ) + } + } + // copied from ModuleUtils private def recursive[T <: String](start: T, deps: T => Seq[T]): Seq[T] = { diff --git a/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala b/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala index 5c78f4138b77..121080cb3017 100644 --- a/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala +++ b/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala @@ -60,7 +60,7 @@ object CompileRunTests extends TestSuite { ) object test extends ScalaNativeTests with TestModule.Utest { - override def sources = Task.Sources { millSourcePath / "src/utest" } + override def sources = Task.Sources { this.millSourcePath / "src/utest" } override def ivyDeps = super.ivyDeps() ++ Agg( ivy"com.lihaoyi::utest::$utestVersion" ) diff --git a/scalanativelib/test/src/mill/scalanativelib/ExclusionsTests.scala b/scalanativelib/test/src/mill/scalanativelib/ExclusionsTests.scala index 4947f2962ccd..d3698c0c5877 100644 --- a/scalanativelib/test/src/mill/scalanativelib/ExclusionsTests.scala +++ b/scalanativelib/test/src/mill/scalanativelib/ExclusionsTests.scala @@ -1,5 +1,6 @@ package mill.scalanativelib +import mill.given import mill.Agg import mill.scalalib._ import mill.define.Discover diff --git a/scalanativelib/test/src/mill/scalanativelib/FeaturesTests.scala b/scalanativelib/test/src/mill/scalanativelib/FeaturesTests.scala index a796c0c9542e..9df8455f8fcb 100644 --- a/scalanativelib/test/src/mill/scalanativelib/FeaturesTests.scala +++ b/scalanativelib/test/src/mill/scalanativelib/FeaturesTests.scala @@ -1,5 +1,6 @@ package mill.scalanativelib +import mill.given import mill.define.Discover import mill.testkit.UnitTester import mill.testkit.TestBaseModule diff --git a/scalanativelib/test/src/mill/scalanativelib/ScalaTestsErrorTests.scala b/scalanativelib/test/src/mill/scalanativelib/ScalaTestsErrorTests.scala index e8b948602960..48c9d85a270a 100644 --- a/scalanativelib/test/src/mill/scalanativelib/ScalaTestsErrorTests.scala +++ b/scalanativelib/test/src/mill/scalanativelib/ScalaTestsErrorTests.scala @@ -17,7 +17,10 @@ object ScalaTestsErrorTests extends TestSuite { } } - override lazy val millDiscover = Discover[this.type] + override lazy val millDiscover = { + import mill.main.TokenReaders.given + Discover[this.type] + } } def tests: Tests = Tests { diff --git a/testkit/src/mill/testkit/IntegrationTester.scala b/testkit/src/mill/testkit/IntegrationTester.scala index 043b530a5c55..982e2ad672fe 100644 --- a/testkit/src/mill/testkit/IntegrationTester.scala +++ b/testkit/src/mill/testkit/IntegrationTester.scala @@ -105,7 +105,7 @@ object IntegrationTester { * Returns the raw text of the `.json` metadata file */ def text: String = { - val Seq((List(selector), _)) = + val Seq((Seq(selector), _)) = mill.resolve.ParseArgs.apply(Seq(selector0), SelectMode.Separated).getOrElse(???) val segments = selector._2.getOrElse(Segments()).value.flatMap(_.pathSegments) diff --git a/testkit/src/mill/testkit/UnitTester.scala b/testkit/src/mill/testkit/UnitTester.scala index 90768b2fc134..3740cf3f24f3 100644 --- a/testkit/src/mill/testkit/UnitTester.scala +++ b/testkit/src/mill/testkit/UnitTester.scala @@ -189,7 +189,7 @@ class UnitTester( } def close(): Unit = { - for ((_, Val(obsolete: AutoCloseable)) <- evaluator.workerCache.values) { + for (case (_, Val(obsolete: AutoCloseable)) <- evaluator.workerCache.values) { obsolete.close() } } From a2e11e6e325133d1ff6f30358bd42e262deec079 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 03:12:52 +0200 Subject: [PATCH 04/13] . --- runner/src/mill/runner/MillBuildRootModule.scala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/runner/src/mill/runner/MillBuildRootModule.scala b/runner/src/mill/runner/MillBuildRootModule.scala index 10ae284a0af1..c4e9f9d918e9 100644 --- a/runner/src/mill/runner/MillBuildRootModule.scala +++ b/runner/src/mill/runner/MillBuildRootModule.scala @@ -243,10 +243,6 @@ abstract class MillBuildRootModule()(implicit Seq( "-Xplugin:" + lineNumberPluginClasspath().map(_.path).mkString(","), "-deprecation", - // Make sure we abort of the plugin is not found, to ensure any - // classpath/plugin-discovery issues are surfaced early rather than - // after hours of debugging - "-Xplugin-require:mill-linenumber-plugin" ) } From 300d692acdf91ee2b5e5cae1c3632403c8e35b81 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 03:29:58 +0200 Subject: [PATCH 05/13] . --- .../realistic/5-parser/src/Hello.scala | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala b/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala index 334525b900e0..52df0ce57f67 100644 --- a/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala +++ b/main/codesig/test/cases/callgraph/realistic/5-parser/src/Hello.scala @@ -6,15 +6,15 @@ class Word(s: String) extends Phrase class Pair(lhs: Phrase, rhs: Phrase) extends Phrase object Parser { - def prefix[_X: P] = P("hello" | "goodbye").!.map(new Word(_)) + def prefix[$: P] = P("hello" | "goodbye").!.map(new Word(_)) - def suffix[_X: P] = P("world" | "seattle").!.map(new Word(_)) + def suffix[$: P] = P("world" | "seattle").!.map(new Word(_)) - def ws[_X: P] = P(" ".rep(1)) + def ws[$: P] = P(" ".rep(1)) - def parened[_X: P] = P("(" ~ parser ~ ")") + def parened[$: P] = P("(" ~ parser ~ ")") - def parser[_X: P]: P[Phrase] = P((parened | prefix) ~ ws ~ (parened | suffix)).map { + def parser[$: P]: P[Phrase] = P((parened | prefix) ~ ws ~ (parened | suffix)).map { case (lhs, rhs) => new Pair(lhs, rhs) } } @@ -24,21 +24,6 @@ object Parser { "hello.Parser$#parened(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Parser$#parser(fastparse.ParsingRun)fastparse.ParsingRun" ], - "hello.Parser$#parse0$proxy8$1(fastparse.ParsingRun)fastparse.ParsingRun": [ - "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" - ], - "hello.Parser$#parse0$proxy9$1(fastparse.ParsingRun)fastparse.ParsingRun": [ - "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" - ], - "hello.Parser$#parse0$proxy9$2(fastparse.ParsingRun)fastparse.ParsingRun": [ - "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" - ], - "hello.Parser$#parse0$proxy9$3(fastparse.ParsingRun)fastparse.ParsingRun": [ - "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" - ], - "hello.Parser$#parse0$proxy9$4(fastparse.ParsingRun)fastparse.ParsingRun": [ - "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" - ], "hello.Parser$#parser(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Pair#(hello.Phrase,hello.Phrase)void", "hello.Parser$#parened(fastparse.ParsingRun)fastparse.ParsingRun", @@ -49,16 +34,9 @@ object Parser { "hello.Parser$#prefix(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Word#(java.lang.String)void" ], - "hello.Parser$#rec$1(fastparse.ParsingRun,int,fastparse.Implicits$Repeater,java.lang.Object,fastparse.ParsingRun,int,int,boolean,boolean,fastparse.internal.Msgs,fastparse.internal.Msgs)fastparse.ParsingRun": [ - "hello.Parser$#end$1(int,fastparse.ParsingRun,fastparse.Implicits$Repeater,java.lang.Object,int,int,int,boolean)fastparse.ParsingRun", - "hello.Parser$#parse0$1$1(fastparse.ParsingRun)fastparse.ParsingRun" - ], "hello.Parser$#suffix(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Word#(java.lang.String)void" ], - "hello.Parser$#ws(fastparse.ParsingRun)fastparse.ParsingRun": [ - "hello.Parser$#rec$1(fastparse.ParsingRun,int,fastparse.Implicits$Repeater,java.lang.Object,fastparse.ParsingRun,int,int,boolean,boolean,fastparse.internal.Msgs,fastparse.internal.Msgs)fastparse.ParsingRun" - ], "hello.Parser.parened(fastparse.ParsingRun)fastparse.ParsingRun": [ "hello.Parser$#()void", "hello.Parser$#parened(fastparse.ParsingRun)fastparse.ParsingRun" From 3eb4c8257d0d49ec52abef3a9beeb5d4c0e2027e Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 03:32:19 +0200 Subject: [PATCH 06/13] . --- .../multi-level-editing/src/MultiLevelBuildTests.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala index c799d0f65876..2f293f7cbf84 100644 --- a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala +++ b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala @@ -336,7 +336,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { // Ensure the file path in the compile error is properly adjusted to point // at the original source file and not the generated file (workspacePath / "build.mill").toString, - "Not found: doesnt" + "Not found: value doesnt" ) checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, false, false) @@ -346,7 +346,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/build.mill").toString, - "Not found: doesnt" + "Not found: object doesnt" ) checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, false) @@ -356,7 +356,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/mill-build/build.mill").toString, - "Not found: doesnt" + "Not found: object doesnt" ) checkWatchedFiles(tester, Nil, Nil, Nil, buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, null) @@ -366,7 +366,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/build.mill").toString, - "Not found: doesnt" + "Not found: object doesnt" ) checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, true) @@ -376,7 +376,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "build.mill").toString, - "Not found: doesnt" + "Not found: value doesnt" ) checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, true, false) From e32cc077996d76e291e3291e639093a133bb11e8 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 03:36:20 +0200 Subject: [PATCH 07/13] . --- .../multi-level-editing/src/MultiLevelBuildTests.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala index 2f293f7cbf84..7c92a4486d49 100644 --- a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala +++ b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala @@ -336,7 +336,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { // Ensure the file path in the compile error is properly adjusted to point // at the original source file and not the generated file (workspacePath / "build.mill").toString, - "Not found: value doesnt" + "not found: value doesnt" ) checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, false, false) @@ -346,7 +346,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/build.mill").toString, - "Not found: object doesnt" + "not found: object doesnt" ) checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, false) @@ -356,7 +356,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/mill-build/build.mill").toString, - "Not found: object doesnt" + "not found: object doesnt" ) checkWatchedFiles(tester, Nil, Nil, Nil, buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, null) @@ -366,7 +366,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "mill-build/build.mill").toString, - "Not found: object doesnt" + "not found: object doesnt" ) checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, null, true) @@ -376,7 +376,7 @@ object MultiLevelBuildTests extends UtestIntegrationTestSuite { tester, "\n1 tasks failed", (workspacePath / "build.mill").toString, - "Not found: value doesnt" + "not found: value doesnt" ) checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) checkChangedClassloaders(tester, null, null, true, false) From 6f6d9f808b025b96b145cfa60de82001b3e3dc2a Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 03:36:56 +0200 Subject: [PATCH 08/13] . --- example/thirdparty/mockito/build.mill | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/thirdparty/mockito/build.mill b/example/thirdparty/mockito/build.mill index 9eab3b2ab0be..ad0fbf5e3b11 100644 --- a/example/thirdparty/mockito/build.mill +++ b/example/thirdparty/mockito/build.mill @@ -43,7 +43,7 @@ trait MockitoModule extends MavenModule{ def testFramework = "com.novocode.junit.JUnitFramework" def testForkArgs: T[Seq[String]] = Seq.empty[String] - def testFilteredSources: T[Seq[PathRef]] = Task { Seq.empty } + def testFilteredSources: T[Seq[PathRef]] = Task { Seq.empty[PathRef] } object test extends MavenTests{ def moduleDeps = super.moduleDeps ++ MockitoModule.this.testModuleDeps From c7e263103452a59c4517a42795bb3e69c41afc52 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 04:20:06 +0200 Subject: [PATCH 09/13] . --- .../linenumbers/resources/scalac-plugin.xml | 4 + .../linenumbers/LineNumberCorrector.scala | 65 +++ .../mill/linenumbers/LineNumberPlugin.scala | 44 ++ .../src/mill/runner/MillBuildRootModule.scala | 4 + .../mill/scalalib/worker/ZincWorkerImpl.scala | 411 ++---------------- 5 files changed, 143 insertions(+), 385 deletions(-) create mode 100644 runner/linenumbers/resources/scalac-plugin.xml create mode 100644 runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala create mode 100644 runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala diff --git a/runner/linenumbers/resources/scalac-plugin.xml b/runner/linenumbers/resources/scalac-plugin.xml new file mode 100644 index 000000000000..7a27d92f3f79 --- /dev/null +++ b/runner/linenumbers/resources/scalac-plugin.xml @@ -0,0 +1,4 @@ + + mill-linenumber-plugin + mill.linenumbers.LineNumberPlugin + \ No newline at end of file diff --git a/runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala b/runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala new file mode 100644 index 000000000000..74fa588f9e3c --- /dev/null +++ b/runner/linenumbers/src/mill/linenumbers/LineNumberCorrector.scala @@ -0,0 +1,65 @@ +package mill.linenumbers + +import scala.tools.nsc.Global + +object LineNumberCorrector { + def apply( + g: Global, + lines: Seq[String], + adjustedFile: String + )(unit: g.CompilationUnit): g.Tree = { + + val userCodeStartMarker = "//MILL_USER_CODE_START_MARKER" + + import scala.reflect.internal.util._ + + val markerLine = lines.indexWhere(_.startsWith(userCodeStartMarker)) + + val topWrapperLen = lines.take(markerLine + 1).map(_.length).sum + + val trimmedSource = new BatchSourceFile( + new scala.reflect.io.PlainFile(adjustedFile), + g.currentSource.content.drop(topWrapperLen) + ) + + import scala.reflect.internal.util._ + object Transformer extends g.Transformer { + override def transform(tree: g.Tree) = { + val transformedTree = super.transform(tree) + // The `start` and `end` values in transparent/range positions are left + // untouched, because of some aggressive validation in scalac that checks + // that trees are not overlapping, and shifting these values here + // violates the invariant (which breaks Ammonite, potentially because + // of multi-stage). + // Moreover, we rely only on the "point" value (for error reporting). + // The ticket https://github.com/scala/scala-dev/issues/390 tracks down + // relaxing the aggressive validation. + val newPos = tree.pos match { + case s: TransparentPosition if s.start > topWrapperLen => + new TransparentPosition( + trimmedSource, + s.start - topWrapperLen, + s.point - topWrapperLen, + s.end - topWrapperLen + ) + case s: RangePosition if s.start > topWrapperLen => + new RangePosition( + trimmedSource, + s.start - topWrapperLen, + s.point - topWrapperLen, + s.end - topWrapperLen + ) + case s: OffsetPosition if s.start > topWrapperLen => + new OffsetPosition(trimmedSource, s.point - topWrapperLen) + case s => s + + } + transformedTree.pos = newPos + + transformedTree + } + } + Transformer.transform(unit.body) + } + +} diff --git a/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala b/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala new file mode 100644 index 000000000000..b8f0aeee877a --- /dev/null +++ b/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala @@ -0,0 +1,44 @@ +package mill.linenumbers + +import mill.main.client.CodeGenConstants.buildFileExtensions +import scala.tools.nsc._ +import scala.tools.nsc.plugins.{Plugin, PluginComponent} + +/** + * Used to capture the names in scope after every execution, reporting them + * to the `output` function. Needs to be a compiler plugin so we can hook in + * immediately after the `typer` + */ +class LineNumberPlugin(val global: Global) extends Plugin { + override def init(options: List[String], error: String => Unit): Boolean = true + val name: String = "mill-linenumber-plugin" + val description = "Adjusts line numbers in the user-provided script to compensate for wrapping" + val components: List[PluginComponent] = List( + new PluginComponent { + val global = LineNumberPlugin.this.global + val runsAfter = List("parser") + val phaseName = "FixLineNumbers" + def newPhase(prev: Phase): Phase = new global.GlobalPhase(prev) { + def name = phaseName + def apply(unit: global.CompilationUnit): Unit = { + LineNumberPlugin.apply(global)(unit) + } + } + } + ) +} + +object LineNumberPlugin { + def apply(g: Global)(unit: g.CompilationUnit): Unit = { + if (buildFileExtensions.exists(ex => g.currentSource.file.name.endsWith(s".$ex"))) { + + val str = new String(g.currentSource.content) + val lines = str.linesWithSeparators.toVector + val adjustedFile = lines + .collectFirst { case s"//MILL_ORIGINAL_FILE_PATH=$rest" => rest.trim } + .getOrElse(sys.error(g.currentSource.path)) + + unit.body = LineNumberCorrector(g, lines, adjustedFile)(unit) + } + } +} diff --git a/runner/src/mill/runner/MillBuildRootModule.scala b/runner/src/mill/runner/MillBuildRootModule.scala index c4e9f9d918e9..10ae284a0af1 100644 --- a/runner/src/mill/runner/MillBuildRootModule.scala +++ b/runner/src/mill/runner/MillBuildRootModule.scala @@ -243,6 +243,10 @@ abstract class MillBuildRootModule()(implicit Seq( "-Xplugin:" + lineNumberPluginClasspath().map(_.path).mkString(","), "-deprecation", + // Make sure we abort of the plugin is not found, to ensure any + // classpath/plugin-discovery issues are surfaced early rather than + // after hours of debugging + "-Xplugin-require:mill-linenumber-plugin" ) } diff --git a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala index 7b53632afd8d..5b7c373992a2 100644 --- a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala +++ b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala @@ -42,7 +42,6 @@ import xsbti.compile.{ import xsbti.{PathBasedFile, VirtualFile} import java.io.{File, PrintWriter} -import java.nio.charset.StandardCharsets import java.util.Optional import scala.annotation.tailrec import scala.collection.mutable @@ -145,7 +144,7 @@ class ZincWorkerImpl( compilerClasspath, scalacPluginClasspath, Seq() - ) { (compilers: Compilers) => + ) { compilers: Compilers => if (ZincWorkerUtil.isDotty(scalaVersion) || ZincWorkerUtil.isScala3Milestone(scalaVersion)) { // dotty 0.x and scala 3 milestones use the dotty-doc tool val dottydocClass = @@ -389,7 +388,7 @@ class ZincWorkerImpl( compilerClasspath = compilerClasspath, scalacPluginClasspath = scalacPluginClasspath, javacOptions = javacOptions - ) { (compilers: Compilers) => + ) { compilers: Compilers => compileInternal( upstreamCompileOutput = upstreamCompileOutput, sources = sources, @@ -496,8 +495,6 @@ class ZincWorkerImpl( auxiliaryClassFileExtensions: Seq[String], zincCache: os.SubPath = os.sub / "zinc" )(implicit ctx: ZincWorkerApi.Ctx): Result[CompilationResult] = { - import ZincWorkerImpl.{ForwardingReporter, TransformingReporter, PositionMapper} - os.makeDir.all(ctx.dest) val classesDir = @@ -528,21 +525,30 @@ class ZincWorkerImpl( val loggerId = Thread.currentThread().getId.toString val logger = SbtLoggerUtils.createLogger(loggerId, consoleAppender, zincLogLevel) - def mkNewReporter(mapper: (xsbti.Position => xsbti.Position)) = reporter match { - case None => - new ManagedLoggedReporter(10, logger) with RecordingReporter - with TransformingReporter { - def color: Boolean = ctx.log.colored - def optPositionMapper = mapper - } - case Some(forwarder0) => - new ManagedLoggedReporter(10, logger) - with ForwardingReporter - with RecordingReporter - with TransformingReporter { - def forwarder = forwarder0 - def color: Boolean = ctx.log.colored - def optPositionMapper = mapper + val newReporter = reporter match { + case None => new ManagedLoggedReporter(10, logger) with RecordingReporter + case Some(forwarder) => + new ManagedLoggedReporter(10, logger) with RecordingReporter { + + override def logError(problem: xsbti.Problem): Unit = { + forwarder.logError(new ZincProblem(problem)) + super.logError(problem) + } + + override def logWarning(problem: xsbti.Problem): Unit = { + forwarder.logWarning(new ZincProblem(problem)) + super.logWarning(problem) + } + + override def logInfo(problem: xsbti.Problem): Unit = { + forwarder.logInfo(new ZincProblem(problem)) + super.logInfo(problem) + } + + override def printSummary(): Unit = { + forwarder.printSummary() + super.printSummary() + } } } val analysisMap0 = upstreamCompileOutput.map(c => c.classes.path -> c.analysisFile).toMap @@ -575,10 +581,6 @@ class ZincWorkerImpl( auxiliaryClassFileExtensions.map(new AuxiliaryClassFileExtension(_)).toArray ) - val newReporter = mkNewReporter( - PositionMapper.create(virtualSources) - ) - val inputs = ic.inputs( classpath = classpath, sources = virtualSources, @@ -671,367 +673,6 @@ class ZincWorkerImpl( } object ZincWorkerImpl { - - /** - * TODO: copied from mill.scalalib.Assembly - */ - private object Streamable { - def bytes(is: java.io.InputStream): Array[Byte] = { - val out = new java.io.ByteArrayOutputStream - mill.api.IO.stream(is, out) - out.close() - out.toByteArray - } - } - - private def intValue(oi: java.util.Optional[Integer], default: Int): Int = { - if (oi.isPresent) oi.get().intValue() - else default - } - - private object PositionMapper { - import sbt.util.InterfaceUtil - - private val userCodeStartMarker = "//MILL_USER_CODE_START_MARKER" - private val splicedCodeStartMarker = "//MILL_SPLICED_CODE_START_MARKER" - private val splicedCodeEndMarker = "//MILL_SPLICED_CODE_END_MARKER" - - /** Transforms positions of problems if coming from a build file. */ - private def lookup(buildSources: Map[String, xsbti.Position => xsbti.Position])( - oldPos: xsbti.Position - ): xsbti.Position = { - val src = oldPos.sourcePath() - if (src.isPresent) { - buildSources.get(src.get()) match { - case Some(f) => f(oldPos) - case _ => oldPos - } - } else { - oldPos - } - } - - def create(sources: Array[VirtualFile]): (xsbti.Position => xsbti.Position) = { - val buildSources0 = { - def isBuild(vf: VirtualFile) = - mill.main.client.CodeGenConstants.buildFileExtensions.exists(ex => - vf.id().endsWith(s".$ex") - ) - - sources.collect({ - case vf if isBuild(vf) => - val str = new String(Streamable.bytes(vf.input()), StandardCharsets.UTF_8) - - val lines = str.linesWithSeparators.toVector - val adjustedFile = lines - .collectFirst { case s"//MILL_ORIGINAL_FILE_PATH=$rest" => rest.trim } - .getOrElse(sys.error(vf.id())) - - vf.id() -> remap(lines, adjustedFile) - }) - } - - if (buildSources0.nonEmpty) lookup(buildSources0.toMap) else null - } - - private def remap( - lines: Vector[String], - adjustedFile: String - ): xsbti.Position => xsbti.Position = { - val markerLine = lines.indexWhere(_.startsWith(userCodeStartMarker)) - val splicedMarkerStartLine = lines.indexWhere(_.startsWith(splicedCodeStartMarker)) - val splicedMarkerLine = lines.indexWhere(_.startsWith(splicedCodeEndMarker)) - val existsSplicedMarker = splicedMarkerStartLine >= 0 && splicedMarkerLine >= 0 - val splicedMarkerLineDiff = markerLine + (splicedMarkerLine - splicedMarkerStartLine + 1) + 1 - - val topWrapperLen = lines.take(markerLine + 1).map(_.length).sum - val splicedMarkerLen = - if (existsSplicedMarker) lines.take(splicedMarkerLine + 1).map(_.length).sum - else -1 - - val originPath = Some(adjustedFile) - val originFile = Some(java.nio.file.Paths.get(adjustedFile).toFile) - - def userCode(offset: java.util.Optional[Integer]): Boolean = - intValue(offset, -1) > topWrapperLen - - def postSplice(offset: Int): Boolean = - existsSplicedMarker && offset > splicedMarkerLen - - def inner(pos0: xsbti.Position): xsbti.Position = { - if (userCode(pos0.startOffset()) || userCode(pos0.offset())) { - val Array(line, offset, startOffset, endOffset, startLine, endLine) = - Array( - pos0.line(), - pos0.offset(), - pos0.startOffset(), - pos0.endOffset(), - pos0.startLine(), - pos0.endLine() - ) - .map(intValue(_, 1) - 1) - - val (baseLine, baseOffset) = - if (postSplice(startOffset) || postSplice(offset)) - (splicedMarkerLineDiff, splicedMarkerLen) - else - (markerLine, topWrapperLen) - - InterfaceUtil.position( - line0 = Some(line - baseLine), - content = pos0.lineContent(), - offset0 = Some(offset - baseOffset), - pointer0 = InterfaceUtil.jo2o(pos0.pointer()), - pointerSpace0 = InterfaceUtil.jo2o(pos0.pointerSpace()), - sourcePath0 = originPath, - sourceFile0 = originFile, - startOffset0 = Some(startOffset - baseOffset), - endOffset0 = Some(endOffset - baseOffset), - startLine0 = Some(startLine - baseLine), - startColumn0 = InterfaceUtil.jo2o(pos0.startColumn()), - endLine0 = Some(endLine - baseLine), - endColumn0 = InterfaceUtil.jo2o(pos0.endColumn()) - ) - } else { - pos0 - } - } - - inner - } - } - - private trait ForwardingReporter extends ManagedLoggedReporter { - def forwarder: CompileProblemReporter - override def logError(problem: xsbti.Problem): Unit = { - forwarder.logError(new ZincProblem(problem)) - super.logError(problem) - } - - override def logWarning(problem: xsbti.Problem): Unit = { - forwarder.logWarning(new ZincProblem(problem)) - super.logWarning(problem) - } - - override def logInfo(problem: xsbti.Problem): Unit = { - forwarder.logInfo(new ZincProblem(problem)) - super.logInfo(problem) - } - - override def printSummary(): Unit = { - forwarder.printSummary() - super.printSummary() - } - } - - private trait TransformingReporter extends xsbti.Reporter { - def color: Boolean - def optPositionMapper: (xsbti.Position => xsbti.Position) - - // Overriding this is necessary because for some reason the LoggedReporter doesn't transform positions - // of Actions and DiagnosticRelatedInformation - abstract override def log(problem0: xsbti.Problem): Unit = { - val localMapper = optPositionMapper - val problem = { - if (localMapper == null) problem0 - else TransformingReporter.transformProblem(color, problem0, localMapper) - } - super.log(problem) - } - } - - private object TransformingReporter { - - import scala.jdk.CollectionConverters._ - import sbt.util.InterfaceUtil - - /** implements a transformation that returns the same object if the mapper has no effect. */ - private def transformProblem( - color: Boolean, - problem0: xsbti.Problem, - mapper: xsbti.Position => xsbti.Position - ): xsbti.Problem = { - val pos0 = problem0.position() - val related0 = problem0.diagnosticRelatedInformation() - val actions0 = problem0.actions() - val pos = mapper(pos0) - val related = transformRelateds(related0, mapper) - val actions = transformActions(actions0, mapper) - val posIsNew = pos ne pos0 - if (posIsNew || (related ne related0) || (actions ne actions0)) { - val rendered = { - // if we transformed the position, then we must re-render the message - if (posIsNew) Some(dottyStyleMessage(color, problem0, pos)) - else InterfaceUtil.jo2o(problem0.rendered()) - } - InterfaceUtil.problem( - cat = problem0.category(), - pos = pos, - msg = problem0.message(), - sev = problem0.severity(), - rendered = rendered, - diagnosticCode = InterfaceUtil.jo2o(problem0.diagnosticCode()), - diagnosticRelatedInformation = anyToList(related), - actions = anyToList(actions) - ) - }else - problem0 - } - - private type JOrSList[T] = AnyRef - - private def anyToList[T](ts: JOrSList[T]): List[T] = ts match { - case ts: List[T] => ts - case ts: java.util.List[T] => ts.asScala.toList - } - - /** Render the message in the style of dotty */ - private def dottyStyleMessage( - color: Boolean, - problem0: xsbti.Problem, - pos: xsbti.Position - ): String = { - val base = problem0.message() - val severity = problem0.severity() - - def shade(msg: String) = - if (color) - severity match { - case xsbti.Severity.Error => Console.RED + msg + Console.RESET - case xsbti.Severity.Warn => Console.YELLOW + msg + Console.RESET - case xsbti.Severity.Info => Console.BLUE + msg + Console.RESET - } - else msg - - val normCode = { - problem0.diagnosticCode().filter(_.code() != "-1").map({ inner => - val prefix = s"[E${inner.code()}] " - inner.explanation().map(e => - s"$prefix$e: " - ).orElse(prefix) - }).orElse("") - } - - val optPath = InterfaceUtil.jo2o(pos.sourcePath()).map { path => - val line0 = intValue(pos.line(), -1) - val pointer0 = intValue(pos.pointer(), -1) - if (line0 >= 0 && pointer0 >= 0) - s"$path:$line0:${pointer0 + 1}" - else - path - } - - val normHeader = optPath.map(path => - s"${shade(s"-- $normCode$path")}\n" - ).getOrElse("") - - val optSnippet = { - val snip = pos.lineContent() - val space = pos.pointerSpace().orElse("") - val pointer = intValue(pos.pointer(), -99) - val endCol = intValue(pos.endColumn(), pointer + 1) - if (snip.nonEmpty && space.nonEmpty && pointer >= 0 && endCol >= 0) { - val arrowCount = math.max(1, math.min(endCol - pointer, snip.length - space.length)) - Some( - s"""$snip - |$space${"^" * arrowCount}""".stripMargin - ) - }else - None - } - - val content = optSnippet match { - case Some(snippet) => - val initial = { - s"""$snippet - |$base - |""".stripMargin - } - val snippetLine = intValue(pos.line(), -1) - if (snippetLine >= 0) { - // add margin with line number - val lines = initial.linesWithSeparators.toVector - val pre = snippetLine.toString - val rest0 = " " * pre.length - val rest = pre +: Vector.fill(lines.size - 1)(rest0) - rest.lazyZip(lines).map((pre, line) => shade(s"$pre │") + line).mkString - } else { - initial - } - case None => - base - } - - normHeader + content - } - - /** Implements a transformation that returns the same list if the mapper has no effect */ - private def transformActions( - actions0: java.util.List[xsbti.Action], - mapper: xsbti.Position => xsbti.Position - ): JOrSList[xsbti.Action] = { - if (actions0.iterator().asScala.exists(a => - a.edit().changes().iterator().asScala.exists(e => - mapper(e.position()) ne e.position() - ) - ) - ) { - actions0.iterator().asScala.map(transformAction(_, mapper)).toList - } else { - actions0 - } - } - - /** Implements a transformation that returns the same list if the mapper has no effect */ - private def transformRelateds( - related0: java.util.List[xsbti.DiagnosticRelatedInformation], - mapper: xsbti.Position => xsbti.Position - ): JOrSList[xsbti.DiagnosticRelatedInformation] = { - - if (related0.iterator().asScala.exists(r => mapper(r.position()) ne r.position())) - related0.iterator().asScala.map(transformRelated(_, mapper)).toList - else - related0 - } - - private def transformRelated( - related0: xsbti.DiagnosticRelatedInformation, - mapper: xsbti.Position => xsbti.Position - ): xsbti.DiagnosticRelatedInformation = { - InterfaceUtil.diagnosticRelatedInformation(mapper(related0.position()), related0.message()) - } - - private def transformAction( - action0: xsbti.Action, - mapper: xsbti.Position => xsbti.Position - ): xsbti.Action = { - InterfaceUtil.action( - title = action0.title(), - description = InterfaceUtil.jo2o(action0.description()), - edit = transformEdit(action0.edit(), mapper) - ) - } - - private def transformEdit( - edit0: xsbti.WorkspaceEdit, - mapper: xsbti.Position => xsbti.Position - ): xsbti.WorkspaceEdit = { - InterfaceUtil.workspaceEdit( - edit0.changes().iterator().asScala.map(transformTEdit(_, mapper)).toList - ) - } - - private def transformTEdit( - edit0: xsbti.TextEdit, - mapper: xsbti.Position => xsbti.Position - ): xsbti.TextEdit = { - InterfaceUtil.textEdit( - position = mapper(edit0.position()), - newText = edit0.newText() - ) - } - } - // copied from ModuleUtils private def recursive[T <: String](start: T, deps: T => Seq[T]): Seq[T] = { From a31128d9ddf88fcf1841749c5b5cdcdf369848b7 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 04:27:51 +0200 Subject: [PATCH 10/13] . --- .../feature/docannotations/src/DocAnnotationsTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/feature/docannotations/src/DocAnnotationsTests.scala b/integration/feature/docannotations/src/DocAnnotationsTests.scala index 4ef2900e86c7..ee3449a00ea8 100644 --- a/integration/feature/docannotations/src/DocAnnotationsTests.scala +++ b/integration/feature/docannotations/src/DocAnnotationsTests.scala @@ -93,7 +93,7 @@ object DocAnnotationsTests extends UtestIntegrationTestSuite { assert( globMatches( - """core.ivyDepsTree(JavaModule.scala:896) + """core.ivyDepsTree(JavaModule.scala:...) | Command to print the transitive dependency tree to STDOUT. | | --inverse Invert the tree representation, so that the root is on the bottom val From 662c117f1bc39787b6c4967be170bb737c6796fb Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 04:37:34 +0200 Subject: [PATCH 11/13] . --- contrib/playlib/src/mill/playlib/RouterModule.scala | 2 +- contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala | 4 ++-- contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/playlib/src/mill/playlib/RouterModule.scala b/contrib/playlib/src/mill/playlib/RouterModule.scala index 67123db1df07..11b921257b5d 100644 --- a/contrib/playlib/src/mill/playlib/RouterModule.scala +++ b/contrib/playlib/src/mill/playlib/RouterModule.scala @@ -81,7 +81,7 @@ trait RouterModule extends ScalaModule with Version { artifactSuffix = playMinorVersion() match { case "2.6" => "_2.12" case "2.7" | "2.8" => "_2.13" - case _ => "_3" + case _ => "_2.13" } ) } diff --git a/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala b/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala index c50199b2f862..718ddf27670e 100644 --- a/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala +++ b/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala @@ -71,7 +71,7 @@ object RouterModuleTests extends TestSuite with PlayTestSuite { val eitherResult = eval.apply(project.compileRouter) val Left(Failure(message, x)) = eitherResult val playExpectedMessage = - if (!playVersion.startsWith("2.7.") && !playVersion.startsWith("2.8.")) { + if (playVersion.startsWith("2.6.")) { "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" } else { "end of input expected" @@ -98,7 +98,7 @@ object RouterModuleTests extends TestSuite with PlayTestSuite { val eitherResult = eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) val Left(Failure(message, x)) = eitherResult val playExpectedMessage = - if (!playVersion.startsWith("2.7.") && !playVersion.startsWith("2.8.")) { + if (playVersion.startsWith("2.6.")) { "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" } else { "end of input expected" diff --git a/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala index d881936fab24..36b0b02c0634 100644 --- a/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala +++ b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala @@ -168,9 +168,9 @@ object HelloWorldTests1_5 extends HelloWorldTests { } object HelloWorldTests1_6 extends HelloWorldTests { override val testTwirlVersion = "1.6.2" - override val wildcard = "*" + override val wildcard = "_" } object HelloWorldTests2_0 extends HelloWorldTests { override val testTwirlVersion = "2.0.1" - override val wildcard = "*" + override val wildcard = "_" } From b3cc906d828c932aff5ecb6ec819fb6fc3df0555 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 07:02:35 +0200 Subject: [PATCH 12/13] . --- main/api/src/mill/api/AggWrapper.scala | 6 +++--- main/resolve/src/mill/resolve/ExpandBraces.scala | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main/api/src/mill/api/AggWrapper.scala b/main/api/src/mill/api/AggWrapper.scala index 31f27082915b..9be41fb579b3 100644 --- a/main/api/src/mill/api/AggWrapper.scala +++ b/main/api/src/mill/api/AggWrapper.scala @@ -33,11 +33,11 @@ private[mill] sealed class AggWrapper(strictUniqueness: Boolean) { def map[T](f: V => T): Agg[T] def filter(f: V => Boolean): Agg[V] - override def collect[T](f: PartialFunction[V, T]): Agg[T] = super.collect(f) - override def zipWithIndex: Agg[(V, Int)] = super.zipWithIndex + def collect[T](f: PartialFunction[V, T]): Agg[T] + def zipWithIndex: Agg[(V, Int)] def reverse: Agg[V] def zip[T](other: Agg[T]): Agg[(V, T)] - // def ++[T >: V](other: IterableOnce[T]): Agg[T] // error overriding final method ++ in trait IterableOps + def ++[T >: V](other: IterableOnce[T]): Agg[T] def length: Int def isEmpty: Boolean def foreach[U](f: V => U): Unit diff --git a/main/resolve/src/mill/resolve/ExpandBraces.scala b/main/resolve/src/mill/resolve/ExpandBraces.scala index fdef17c5a1f1..b0d7dc4ecbb6 100644 --- a/main/resolve/src/mill/resolve/ExpandBraces.scala +++ b/main/resolve/src/mill/resolve/ExpandBraces.scala @@ -10,7 +10,7 @@ private object ExpandBraces { case class Expand(values: List[List[Fragment]]) extends Fragment } - private[ExpandBraces] def expandRec(frags: List[Fragment]): List[List[String]] = frags match { + def expandRec(frags: List[Fragment]): List[List[String]] = frags match { case Nil => List(List()) case head :: tail => val tailStrings = expandRec(tail) From b9806501ed062c356a4eb991c0a2649f358c81f9 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 12 Oct 2024 07:55:23 +0200 Subject: [PATCH 13/13] . --- bsp/src/mill/bsp/BSP.scala | 2 +- idea/src/mill/idea/GenIdea.scala | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bsp/src/mill/bsp/BSP.scala b/bsp/src/mill/bsp/BSP.scala index 285383bb8758..4eea72bc9b33 100644 --- a/bsp/src/mill/bsp/BSP.scala +++ b/bsp/src/mill/bsp/BSP.scala @@ -1,7 +1,7 @@ package mill.bsp import mill.api.{Ctx, PathRef} -import mill.{Agg, T, Task, given} +import mill.{Agg, T, Task} import mill.define.{Command, Discover, ExternalModule} import mill.main.BuildInfo import mill.eval.Evaluator diff --git a/idea/src/mill/idea/GenIdea.scala b/idea/src/mill/idea/GenIdea.scala index 66c3f76224db..31b7fab6ebe2 100644 --- a/idea/src/mill/idea/GenIdea.scala +++ b/idea/src/mill/idea/GenIdea.scala @@ -1,6 +1,5 @@ package mill.idea -import mill.given import mill.Task import mill.api.Result import mill.define.{Command, Discover, ExternalModule}