From 0c97f764fec6881abc812e0066cdebb3e0c6ce8a Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sun, 27 Nov 2016 15:24:22 +0100 Subject: [PATCH 01/14] Remove hardcoded classpath reordering If something needs to be fixed, fix it at the source. This prevented dotty-compiler-bootstrapped from using the dotty-library-bootstrapped clases instead of the dotty-library jar --- compiler/src/dotty/tools/dotc/config/JavaPlatform.scala | 2 -- compiler/src/dotty/tools/dotc/config/PathResolver.scala | 9 +-------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala index b5bfbb39fdbd..59201687a41d 100644 --- a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -17,8 +17,6 @@ class JavaPlatform extends Platform { if (currentClassPath.isEmpty) currentClassPath = Some(new PathResolver().result) val cp = currentClassPath.get - //println(cp) - //println("------------------") cp } diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index 8df9a8c0ecf8..184b3718a486 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -255,14 +255,7 @@ class PathResolver(implicit ctx: Context) { def containers = Calculated.containers lazy val result: JavaClassPath = { - // Prioritize `dotty.jar` and `dotty-lib.jar` to shadow others - val (dottyJars, others) = - containers.partition(x => x.name.contains("dotty-lib.jar") || x.name.contains("dotty.jar")) - // Then any jars with `dotty` in the name - putting them before scala-library - val (dottyCp, remaining) = - others.partition(_.name.contains("dotty-")) - - val cp = new JavaClassPath((dottyJars ++ dottyCp ++ remaining).toIndexedSeq, context) + val cp = new JavaClassPath(containers.toIndexedSeq, context) if (settings.Ylogcp.value) { Console.println("Classpath built from " + settings.toConciseString(ctx.sstate)) From 6419a0668b3d4e0bfd42f9a1f69fde66a3944fd6 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 11 Jan 2017 04:05:49 +0100 Subject: [PATCH 02/14] Do not hardcode jars path in the tests, instead get them from sbt This is necessary to run the tests with the bootstrapped projects and is just much better than hardcoding them anyway. --- compiler/test/dotty/Jars.scala | 20 +++++++++----------- project/Build.scala | 10 ++++++++-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/compiler/test/dotty/Jars.scala b/compiler/test/dotty/Jars.scala index 6fc9b0fde8e1..f062f8b25193 100644 --- a/compiler/test/dotty/Jars.scala +++ b/compiler/test/dotty/Jars.scala @@ -1,20 +1,18 @@ package dotty -/** Jars used when compiling test, defaults to sbt locations */ +/** Jars used when compiling test, normally set from the sbt build */ object Jars { - val dottyLib: String = sys.env.get("DOTTY_LIB") getOrElse { - "../library/target/scala-2.11/dotty-library_2.11-0.1.1-SNAPSHOT.jar" - } + val dottyLib: String = sys.env.get("DOTTY_LIB") + .getOrElse(sys.props("dotty.tests.classes.library")) - val dottyCompiler: String = sys.env.get("DOTTY_COMPILER") getOrElse { - "./target/scala-2.11/dotty-compiler_2.11-0.1.1-SNAPSHOT.jar" - } + val dottyCompiler: String = sys.env.get("DOTTY_COMPILER") + .getOrElse(sys.props("dotty.tests.classes.compiler")) - val dottyInterfaces: String = sys.env.get("DOTTY_INTERFACE") getOrElse { - "../interfaces/target/dotty-interfaces-0.1.1-SNAPSHOT.jar" - } + val dottyInterfaces: String = sys.env.get("DOTTY_INTERFACE") + .getOrElse(sys.props("dotty.tests.classes.interfaces")) - val dottyExtras: List[String] = sys.env.get("DOTTY_EXTRAS") + val dottyExtras: List[String] = Option(sys.env.get("DOTTY_EXTRAS") + .getOrElse(sys.props("dotty.tests.extraclasspath"))) .map(_.split(":").toList).getOrElse(Nil) val dottyReplDeps: List[String] = dottyLib :: dottyExtras diff --git a/project/Build.scala b/project/Build.scala index af862817c37c..de4ab563f10e 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -326,7 +326,7 @@ object DottyBuild extends Build { // http://grokbase.com/t/gg/simple-build-tool/135ke5y90p/sbt-setting-jvm-boot-paramaters-for-scala // packageAll should always be run before tests - javaOptions <++= (dependencyClasspath in Runtime, packageAll) map { (attList, _) => + javaOptions <++= (dependencyClasspath in Runtime, packageAll) map { (attList, pA) => // put needed dependencies on classpath: val path = for { file <- attList.map(_.data) @@ -356,7 +356,13 @@ object DottyBuild extends Build { List("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1") else List() - ("-DpartestParentID=" + pid) :: tuning ::: agentOptions ::: ci_build ::: path.toList + val jars = List( + "-Ddotty.tests.classes.interfaces=" + pA("dotty-interfaces"), + "-Ddotty.tests.classes.library=" + pA("dotty-library"), + "-Ddotty.tests.classes.compiler=" + pA("dotty-compiler") + ) + + ("-DpartestParentID=" + pid) :: jars ::: tuning ::: agentOptions ::: ci_build ::: path.toList } ). settings(publishing) From cbe6846fc789f2f5e233e82972e38ee672fa3931 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 11 Jan 2017 00:50:50 +0100 Subject: [PATCH 03/14] Add sbt-based bootstrap This adds two new project to the sbt build: dotty-library-bootstrapped and dotty-compiler bootstrapped. These projects use the same source files as dotty-library and dotty-compiler but are compiled using dotty itself. The main usecase for this is that we can now run the JUnit tests (which are _not_ just a subset of the tests run by partest, for example the REPL tests are only run through JUnit) with a bootstrapped compiler: $ sbt > publishLocal # Non-bootstrapped dotty needs to be published first > dotty-compiler-bootstrapped/test But this also allows one to experiment with a bootstrapped dotty much more easily in general. This revealed many issues in the compiler that are fixed in subsequent commits in this PR. --- project/Build.scala | 146 +++++++++++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 50 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index de4ab563f10e..4c8854267f0c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -11,8 +11,17 @@ import sbt.Package.ManifestAttributes object DottyBuild extends Build { - val baseVersion = "0.1.1" - val isNightly = sys.env.get("NIGHTLYBUILD") == Some("yes") + val scalacVersion = "2.11.5" + + val dottyOrganization = "ch.epfl.lamp" + val dottyVersion = { + val baseVersion = "0.1.1" + val isNightly = sys.env.get("NIGHTLYBUILD") == Some("yes") + if (isNightly) + baseVersion + "-" + VersionUtil.commitDate + "-" + VersionUtil.gitHash + "-NIGHTLY" + else + baseVersion + "-SNAPSHOT" + } val jenkinsMemLimit = List("-Xmx1500m") @@ -45,14 +54,9 @@ object DottyBuild extends Build { override def settings: Seq[Setting[_]] = { super.settings ++ Seq( - scalaVersion in Global := "2.11.5", - version in Global := { - if (isNightly) - baseVersion + "-" + VersionUtil.commitDate + "-" + VersionUtil.gitHash + "-NIGHTLY" - else - baseVersion + "-SNAPSHOT" - }, - organization in Global := "ch.epfl.lamp", + scalaVersion in Global := scalacVersion, + version in Global := dottyVersion, + organization in Global := dottyOrganization, organizationName in Global := "LAMP/EPFL", organizationHomepage in Global := Some(url("http://lamp.epfl.ch")), homepage in Global := Some(url("https://github.com/lampepfl/dotty")), @@ -82,6 +86,17 @@ object DottyBuild extends Build { resourceDirectory in Compile := baseDirectory.value / "resources" ) + // Settings used by all dotty-compiled projects + lazy val commonBootstrappedSettings = Seq( + scalaOrganization := dottyOrganization, + scalaVersion := dottyVersion, + scalaBinaryVersion := "2.11", + scalaCompilerBridgeSource := + (dottyOrganization % "dotty-sbt-bridge" % scalaVersion.value % "component").sources(), + + // sbt gets very unhappy if two projects use the same target + target := baseDirectory.value / ".." / "out" / name.value + ) /** Projects -------------------------------------------------------------- */ @@ -141,25 +156,8 @@ object DottyBuild extends Build { ). settings(publishing) - lazy val `dotty-compiler` = project.in(file("compiler")). - dependsOn(`dotty-interfaces`). - dependsOn(`dotty-library`). - settings(sourceStructure). - settings( - overrideScalaVersionSetting, - - // Disable scaladoc generation, it's way too slow and we'll replace it - // by dottydoc anyway. We still publish an empty -javadoc.jar to make - // sonatype happy. - sources in (Compile, doc) := Seq(), - - // necessary evil: dottydoc currently needs to be included in the dotty - // project, for sbt integration - unmanagedSourceDirectories in Compile := Seq((scalaSource in Compile).value), - unmanagedSourceDirectories in Compile += baseDirectory.value / ".." / "doc-tool" / "src", - unmanagedSourceDirectories in Test := Seq((scalaSource in Test).value), - unmanagedSourceDirectories in Test += baseDirectory.value / ".." / "doc-tool" / "test", - + // Settings shared between dotty-compiler and dotty-compiler-bootstrapped + lazy val dottyCompilerSettings = Seq( // set system in/out for repl connectInput in run := true, outputStrategy := Some(StdoutOutput), @@ -178,28 +176,18 @@ object DottyBuild extends Build { // get libraries onboard partestDeps := Seq(scalaCompiler, - "org.scala-lang" % "scala-reflect" % scalaVersion.value, - "org.scala-lang" % "scala-library" % scalaVersion.value % "test"), + "org.scala-lang" % "scala-reflect" % scalacVersion, + "org.scala-lang" % "scala-library" % scalacVersion % "test"), libraryDependencies ++= partestDeps.value, libraryDependencies ++= Seq("org.scala-lang.modules" %% "scala-xml" % "1.0.1", "org.scala-lang.modules" %% "scala-partest" % "1.0.11" % "test", - "ch.epfl.lamp" % "dottydoc-client" % "0.1.0", + dottyOrganization % "dottydoc-client" % "0.1.0", "com.novocode" % "junit-interface" % "0.11" % "test", "com.github.spullara.mustache.java" % "compiler" % "0.9.3", "com.typesafe.sbt" % "sbt-interface" % sbtVersion.value), // enable improved incremental compilation algorithm incOptions := incOptions.value.withNameHashing(true), - // packageAll packages all and then returns a map with the abs location - packageAll := { - Map( - "dotty-interfaces" -> (packageBin in (`dotty-interfaces`, Compile)).value, - "dotty-compiler" -> (packageBin in Compile).value, - "dotty-library" -> (packageBin in (`dotty-library`, Compile)).value, - "dotty-compiler-test" -> (packageBin in Test).value - ) map { case (k, v) => (k, v.getAbsolutePath) } - }, - // For convenience, change the baseDirectory when running the compiler baseDirectory in (Compile, run) := baseDirectory.value / "..", // .. but not when running partest @@ -274,8 +262,8 @@ object DottyBuild extends Build { val args = Def.spaceDelimited("").parsed val jars = List( (packageBin in Compile).value.getAbsolutePath, - (packageBin in (`dotty-library`, Compile)).value.getAbsolutePath, - (packageBin in (`dotty-interfaces`, Compile)).value.getAbsolutePath + packageAll.value("dotty-library"), + packageAll.value("dotty-interfaces") ) ++ getJarPaths(partestDeps.value, ivyPaths.value.ivyHome) val dottyJars = s"""-dottyJars ${jars.length + 2} dotty.jar dotty-lib.jar ${jars.mkString(" ")}""" @@ -364,9 +352,59 @@ object DottyBuild extends Build { ("-DpartestParentID=" + pid) :: jars ::: tuning ::: agentOptions ::: ci_build ::: path.toList } + ) + + lazy val `dotty-compiler` = project.in(file("compiler")). + dependsOn(`dotty-interfaces`). + dependsOn(`dotty-library`). + settings(sourceStructure). + settings(dottyCompilerSettings). + settings( + overrideScalaVersionSetting, + + // necessary evil: dottydoc currently needs to be included in the dotty + // project, for sbt integration + // FIXME: note part of dottyCompilerSettings because the doc-tool does not + // compile with dotty + unmanagedSourceDirectories in Compile := Seq((scalaSource in Compile).value), + unmanagedSourceDirectories in Compile += baseDirectory.value / ".." / "doc-tool" / "src", + unmanagedSourceDirectories in Test := Seq((scalaSource in Test).value), + unmanagedSourceDirectories in Test += baseDirectory.value / ".." / "doc-tool" / "test", + + // Disable scaladoc generation, it's way too slow and we'll replace it + // by dottydoc anyway. We still publish an empty -javadoc.jar to make + // sonatype happy. + sources in (Compile, doc) := Seq(), + + // packageAll packages all and then returns a map with the abs location + packageAll := { + Map( + "dotty-interfaces" -> (packageBin in (`dotty-interfaces`, Compile)).value, + "dotty-compiler" -> (packageBin in Compile).value, + "dotty-library" -> (packageBin in (`dotty-library`, Compile)).value, + "dotty-compiler-test" -> (packageBin in Test).value + ) map { case (k, v) => (k, v.getAbsolutePath) } + } ). settings(publishing) + lazy val `dotty-compiler-bootstrapped` = project.in(file("compiler")). + dependsOn(`dotty-library-bootstrapped`). + settings(sourceStructure). + settings(commonBootstrappedSettings). + settings(dottyCompilerSettings). + settings( + // Used instead of "dependsOn(`dotty-interfaces`)" because the latter breaks sbt somehow + libraryDependencies += scalaOrganization.value % "dotty-interfaces" % version.value, + + packageAll := { + (packageAll in `dotty-compiler`).value ++ Seq( + ("dotty-compiler" -> (packageBin in Compile).value.getAbsolutePath), + ("dotty-library" -> (packageBin in (`dotty-library-bootstrapped`, Compile)).value.getAbsolutePath) + ) + } + ) + /* Contains unit tests for the scripts */ lazy val `dotty-bin-tests` = project.in(file("bin")). settings(sourceStructure). @@ -377,17 +415,25 @@ object DottyBuild extends Build { "com.novocode" % "junit-interface" % "0.11" % "test" ) - lazy val `dotty-library` = project.in(file("library")). - settings(sourceStructure). - settings( + // Settings shared between dotty-library and dotty-library-bootstrapped + lazy val dottyLibrarySettings = Seq( libraryDependencies ++= Seq( - "org.scala-lang" % "scala-reflect" % scalaVersion.value, - "org.scala-lang" % "scala-library" % scalaVersion.value, + "org.scala-lang" % "scala-reflect" % scalacVersion, + "org.scala-lang" % "scala-library" % scalacVersion, "com.novocode" % "junit-interface" % "0.11" % "test" ) - ). + ) + + lazy val `dotty-library` = project.in(file("library")). + settings(sourceStructure). + settings(dottyLibrarySettings). settings(publishing) + lazy val `dotty-library-bootstrapped` = project.in(file("library")). + settings(sourceStructure). + settings(commonBootstrappedSettings). + settings(dottyLibrarySettings) + // until sbt/sbt#2402 is fixed (https://github.com/sbt/sbt/issues/2402) lazy val cleanSbtBridge = TaskKey[Unit]("cleanSbtBridge", "delete dotty-sbt-bridge cache") From c3f20b61b90db0556272931cb661ef56e92b68d3 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 11 Jan 2017 06:18:58 +0100 Subject: [PATCH 04/14] Enable sbt-based bootstrap in the CI --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index 0b927794ed79..96c5d0b54e8b 100644 --- a/.drone.yml +++ b/.drone.yml @@ -10,5 +10,6 @@ pipeline: matrix: TEST: - test + - dotty-compiler-bootstrapped/test - partest-only-no-bootstrap --show-diff --verbose - partest-only --show-diff --verbose From adc370df8a584096467ba567c0b75d7cec36fd81 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 11 Jan 2017 00:57:59 +0100 Subject: [PATCH 05/14] Use new sbt-based bootstrap for partest too `partest` and `partest-only` are now run through `dotty-compiler-bootstrapped`. The old bootstrapping mechanism is deleted since it has been unmaintained and broken for several months and that I do not wish to maintain two bootstrapping mechanisms. --- compiler/test/dotc/build.scala | 40 ---------------------------------- project/Build.scala | 19 +++++++--------- 2 files changed, 8 insertions(+), 51 deletions(-) delete mode 100644 compiler/test/dotc/build.scala diff --git a/compiler/test/dotc/build.scala b/compiler/test/dotc/build.scala deleted file mode 100644 index b1c8db7c7a0f..000000000000 --- a/compiler/test/dotc/build.scala +++ /dev/null @@ -1,40 +0,0 @@ -package dotc - -import java.io.File - -object build extends tests { - - private def deleteFilesInFolder(folder: File, deleteFolder: Boolean = false): Unit = { - val files = folder.listFiles() - if(files != null) { //some JVMs return null for empty dirs - for(f <- files) { - if(f.isDirectory) { - deleteFilesInFolder(f, deleteFolder = true) - } else { - f.delete() - } - } - } - if(deleteFolder) folder.delete() - } - - def clearOutput() = { - deleteFilesInFolder(new File(defaultOutputDir)) // clear previous output - val keepFile = new File(defaultOutputDir + ".keep") - keepFile.createNewFile() - } - - def main(args: Array[String]): Unit = { - println("---------- Building bootstrapped dotty-lib ----------------------------------------------") - clearOutput() - dottyBootedLib - val p1 = Runtime.getRuntime.exec(Array("jar", "cf", "dotty-lib.jar", "-C", "out", ".")) - p1.waitFor() - - println("---------- Building bootstrapped dotty depending on dotty-lib compiled by dotty ----------") - clearOutput() - dottyDependsOnBootedLib - val p2 = Runtime.getRuntime.exec(Array("jar", "cf", "dotty.jar", "-C", "out", ".")) - p2.waitFor() - } -} diff --git a/project/Build.scala b/project/Build.scala index 4c8854267f0c..a24fc5371ad5 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -119,23 +119,20 @@ object DottyBuild extends Build { addCommandAlias("run", "dotty-compiler/run") ++ addCommandAlias( "partest", - ";packageAll" + - ";dotty-compiler/test:runMain dotc.build" + - ";dotty-compiler/lockPartestFile" + - ";dotty-compiler/test:test" + - ";dotty-compiler/runPartestRunner" + ";publishLocal" + // Non-bootstrapped dotty needs to be published first + ";dotty-compiler-bootstrapped/lockPartestFile" + + ";dotty-compiler-bootstrapped/test:test" + + ";dotty-compiler-bootstrapped/runPartestRunner" ) ++ addCommandAlias( "partest-only", - ";packageAll" + - ";dotty-compiler/test:runMain dotc.build" + - ";dotty-compiler/lockPartestFile" + - ";dotty-compiler/test:test-only dotc.tests" + - ";dotty-compiler/runPartestRunner" + ";publishLocal" + // Non-bootstrapped dotty needs to be published first + ";dotty-compiler-bootstrapped/lockPartestFile" + + ";dotty-compiler-bootstrapped/test:test-only dotc.tests" + + ";dotty-compiler-bootstrapped/runPartestRunner" ) ++ addCommandAlias( "partest-only-no-bootstrap", - ";packageAll" + ";dotty-compiler/lockPartestFile" + ";dotty-compiler/test:test-only dotc.tests" + ";dotty-compiler/runPartestRunner" From d71be28057621750f1ccb168f538c6d942935cac Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Tue, 29 Nov 2016 20:08:23 +0100 Subject: [PATCH 06/14] Fix some dotty compilation errors --- compiler/src/dotty/tools/dotc/parsing/Scanners.scala | 3 ++- compiler/test/dotc/tests.scala | 2 +- compiler/test/dotty/partest/DPConsoleRunner.scala | 9 +++++++-- .../dotty/tools/dotc/parsing/ModifiersParsingTest.scala | 4 ++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 101be167e464..b7516979211a 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -567,7 +567,8 @@ object Scanners { nextChar() getOperatorRest() } else { - error(f"illegal character '\\u${ch: Int}%04x'") + // FIXME: Dotty deviation: f"" interpolator is not supported (#1814) + error("illegal character '\\u%04x'".format(ch: Int)) nextChar() } } diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index 608132bca93e..6ef6bb7413d0 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -61,7 +61,7 @@ class tests extends CompilerTest { List("-classpath", paths) } - implicit val defaultOptions = noCheckOptions ++ { + implicit val defaultOptions: List[String] = noCheckOptions ++ { if (isRunByJenkins) List("-Ycheck:tailrec,resolveSuper,mixin,restoreScopes,labelDef") // should be Ycheck:all, but #725 else List("-Ycheck:tailrec,resolveSuper,mixin,restoreScopes,labelDef") } ++ checkOptions ++ classPath diff --git a/compiler/test/dotty/partest/DPConsoleRunner.scala b/compiler/test/dotty/partest/DPConsoleRunner.scala index f418d2c37725..0ad573792448 100644 --- a/compiler/test/dotty/partest/DPConsoleRunner.scala +++ b/compiler/test/dotty/partest/DPConsoleRunner.scala @@ -202,7 +202,7 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn import FileManager.joinPaths // compile using command-line javac compiler val args = Seq( - javacCmdPath, + suiteRunner.javacCmdPath, // FIXME: Dotty deviation just writing "javacCmdPath" doesn't work "-d", outDir.getAbsolutePath, "-classpath", @@ -398,8 +398,13 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn override def extraClasspath = suiteRunner.fileManager.asInstanceOf[DottyFileManager].extraJarList ::: super.extraClasspath + + // FIXME: Dotty deviation: error if return type is omitted: + // overriding method cleanup in class Runner of type ()Unit; + // method cleanup of type => Boolean | Unit has incompatible type + // override to keep class files if failed and delete clog if ok - override def cleanup = if (lastState.isOk) { + override def cleanup: Unit = if (lastState.isOk) { logFile.delete cLogFile.delete Directory(outDir).deleteRecursively diff --git a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala index 32f842e9252c..806e1af46421 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala @@ -10,11 +10,11 @@ import ast.untpd._ import ast.{ Trees => d } import Parsers.Parser import util.SourceFile -import core.Contexts.ContextBase +import core.Contexts._ import core.Flags object ModifiersParsingTest { - implicit val ctx = (new ContextBase).initialCtx + implicit val ctx: Context = (new ContextBase).initialCtx implicit def parse(code: String): Tree = { val (_, stats) = new Parser(new SourceFile("", code.toCharArray)).templateStatSeq() From 8d603d815d6c7caee05cf34402273fd4108c4efb Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 11 Jan 2017 01:21:46 +0100 Subject: [PATCH 07/14] dotty.ShowTests: fix cyclic references involving implicit values As reportd by dotty (same thing with showShop): cyclic reference involving implicit value showCar This happens when the right hand-side of value showCar's definition involves an implicit search. To avoid the error, give value showCar an explicit type. --- library/test/dotty/ShowTests.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/test/dotty/ShowTests.scala b/library/test/dotty/ShowTests.scala index 7230106d5b6d..b050ad3ee408 100644 --- a/library/test/dotty/ShowTests.scala +++ b/library/test/dotty/ShowTests.scala @@ -35,13 +35,13 @@ class ShowTests { @Test def showCar = { case class Car(model: String, manufacturer: String, year: Int) - implicit val showCar = new Show[Car] { + implicit val showCar: Show[Car] = new Show[Car] { def show(c: Car) = "Car(" + c.model.show + ", " + c.manufacturer.show + ", " + c.year.show + ")" } case class Shop(xs: List[Car], name: String) - implicit val showShop = new Show[Shop] { + implicit val showShop: Show[Shop] = new Show[Shop] { def show(sh: Shop) = "Shop(" + sh.xs.show + ", " + sh.name.show + ")" } From cb2c2a0ff1631df91f84a85b0db814b24a4d6d62 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sun, 4 Dec 2016 22:23:02 +0100 Subject: [PATCH 08/14] Workaround #1770: Run changeOwner at group end in ElimByName Using changeOwnerAfter would be more appropriate but currently fails with an assertion in LambdaLift --- compiler/src/dotty/tools/dotc/transform/ElimByName.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala index 2814baf1e06d..0e187fc2eb27 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala @@ -81,7 +81,11 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform val inSuper = if (ctx.mode.is(Mode.InSuperCall)) InSuperCall else EmptyFlags val meth = ctx.newSymbol( ctx.owner, nme.ANON_FUN, Synthetic | Method | inSuper, MethodType(Nil, Nil, argType)) - Closure(meth, _ => arg.changeOwner(ctx.owner, meth)) + Closure(meth, _ => + atGroupEnd { implicit ctx: Context => + arg.changeOwner(ctx.owner, meth) + } + ) } ref(defn.dummyApply).appliedToType(argType).appliedTo(argFun) case _ => From 779c96bef04d81048f91135b386bd7f37fcf1f20 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sun, 27 Nov 2016 17:19:57 +0100 Subject: [PATCH 09/14] Fix bug in partest.DPConsoleRunner The bug was that we declared case classes like: case class CompFailed() extends NegTestState but we used their companion objects like in: case _ => CompFailed Interestingly, this bug was caught by compiling this code with dotty, instead of `failureStates` getting inferred to be of type `AnyRef`, it ended up being a union of object types, this allows dotty to realize our subsequent pattern match on `failureStates` cannot possibly succeed: -- Error: /home/smarter/opt/dotty/compiler/test/dotty/partest/DPConsoleRunner.scala 353 | case CompFailedButWrongDiff() => | ^ | missing parameter type for parameter x$1 of expanded function x$1 => | x$1 @unchecked match | { | case CompFailedButWrongDiff() => | nextTestActionFailing(s"output differs") | true | case _ => | false | }, expected = ? -- Error: /home/smarter/opt/dotty/compiler/test/dotty/partest/DPConsoleRunner.scala 353 | case CompFailedButWrongDiff() => | ^^^^^^^^^^^^^^^^^^^^^^^^ |Pattern type CompFailedButWrongDiff is neither a subtype nor a supertype of selector type CompSucceeded | CompFailedButWrongNErr | CompFailed | CompFailedButWrongDiff'where: CompFailedButWrongDiff is a class in method runNegTest | CompFailedButWrongDiff' is a object in method runNegTest --- compiler/test/dotty/partest/DPConsoleRunner.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/test/dotty/partest/DPConsoleRunner.scala b/compiler/test/dotty/partest/DPConsoleRunner.scala index 0ad573792448..7a25af6b782a 100644 --- a/compiler/test/dotty/partest/DPConsoleRunner.scala +++ b/compiler/test/dotty/partest/DPConsoleRunner.scala @@ -300,11 +300,11 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn // Don't get confused, the neg test passes when compilation fails for at // least one round (optionally checking the number of compiler errors and // compiler console output) - case class CompFailed() extends NegTestState + case object CompFailed extends NegTestState // the neg test fails when all rounds return either of these: case class CompFailedButWrongNErr(expected: String, found: String) extends NegTestState - case class CompFailedButWrongDiff() extends NegTestState - case class CompSucceeded() extends NegTestState + case object CompFailedButWrongDiff extends NegTestState + case object CompSucceeded extends NegTestState def nerrIsOk(reason: String) = { val nerrFinder = """compilation failed with (\d+) errors""".r @@ -350,7 +350,7 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn if (existsNerr) false else { val existsDiff = failureStates.exists({ - case CompFailedButWrongDiff() => + case CompFailedButWrongDiff => nextTestActionFailing(s"output differs") true case _ => From dc5ba9d2ba31b2fe27f5b967c9fb800bc9210a93 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Tue, 10 Jan 2017 22:36:30 +0100 Subject: [PATCH 10/14] Workaroud #1856: recursively calling a lazy val works differently in Dotty --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 12 +++++++++++- compiler/src/dotty/tools/dotc/typer/ImportInfo.scala | 11 ++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 134b31519258..0aeb28d36397 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -319,7 +319,17 @@ class Definitions { def staticsMethodRef(name: PreName) = ScalaStaticsModule.requiredMethodRef(name) def staticsMethod(name: PreName) = ScalaStaticsModule.requiredMethod(name) - lazy val DottyPredefModuleRef = ctx.requiredModuleRef("dotty.DottyPredef") + // Dotty deviation: we cannot use a lazy val here because lazy vals in dotty + // will return "null" when called recursively, see #1856. + def DottyPredefModuleRef = { + if (myDottyPredefModuleRef == null) { + myDottyPredefModuleRef = ctx.requiredModuleRef("dotty.DottyPredef") + assert(myDottyPredefModuleRef != null) + } + myDottyPredefModuleRef + } + private[this] var myDottyPredefModuleRef: TermRef = _ + def DottyPredefModule(implicit ctx: Context) = DottyPredefModuleRef.symbol def Predef_eqAny(implicit ctx: Context) = DottyPredefModule.requiredMethod(nme.eqAny) diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index a5657890e47e..f7efb2ac2bd4 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -30,7 +30,16 @@ object ImportInfo { class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], symNameOpt: Option[TermName], val isRootImport: Boolean = false)(implicit ctx: Context) { - lazy val sym = symf + // Dotty deviation: we cannot use a lazy val here for the same reason + // that we cannot use one for `DottyPredefModuleRef`. + def sym = { + if (mySym == null) { + mySym = symf + assert(mySym != null) + } + mySym + } + private[this] var mySym: Symbol = _ /** The (TermRef) type of the qualifier of the import clause */ def site(implicit ctx: Context): Type = { From 51a458efeeebfeed6c357d56cf8afe5b06e86724 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 23 Dec 2016 15:49:15 +0100 Subject: [PATCH 11/14] Workaround #1895: Bringing a symbol to a new run is broken --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 10 +++++++--- .../dotty/tools/dotc/transform/ExtensionMethods.scala | 9 +++++++-- tests/repl/vc.check | 5 +++++ 3 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 tests/repl/vc.check diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index aaae78c5714b..a3475e14c60d 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -45,9 +45,13 @@ trait SymDenotations { this: Context => else { val initial = denot.initial val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id) - if ((initial ne denot) || ctx.phaseId != firstPhaseId) - ctx.withPhase(firstPhaseId).stillValidInOwner(initial) - else + if ((initial ne denot) || ctx.phaseId != firstPhaseId) { + ctx.withPhase(firstPhaseId).stillValidInOwner(initial) || + // Workaround #1895: A symbol might not be entered into an owner + // until the second phase where it exists + (denot.validFor.containsPhaseId(firstPhaseId + 1)) && + ctx.withPhase(firstPhaseId + 1).stillValidInOwner(initial) + } else stillValidInOwner(denot) } diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 925ec08b2178..64474cecdf00 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -63,8 +63,13 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful // not generate them again. if (!(valueClass is Scala2x)) ctx.atPhase(thisTransformer) { implicit ctx => for (decl <- valueClass.classInfo.decls) { - if (isMethodWithExtension(decl)) - decls1.enter(createExtensionMethod(decl, moduleClassSym.symbol)) + if (isMethodWithExtension(decl)) { + val meth = createExtensionMethod(decl, moduleClassSym.symbol) + decls1.enter(meth) + // Workaround #1895: force denotation of `meth` to be + // at phase where `meth` is entered into the decls of a class + meth.denot(ctx.withPhase(thisTransformer.next)) + } } } diff --git a/tests/repl/vc.check b/tests/repl/vc.check new file mode 100644 index 000000000000..e2c9b65fda1e --- /dev/null +++ b/tests/repl/vc.check @@ -0,0 +1,5 @@ +scala> class Foo(x: Int) extends AnyVal { def hi: Int = 1 } +defined class Foo +scala> new Foo(1).hi +val res0: Int = 1 +scala> :quit From 57641b9c7447fa0a6f1f47352dffb4c56c560b6a Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sun, 27 Nov 2016 03:17:40 +0100 Subject: [PATCH 12/14] sbt.ExtractDependencies: avoid false dependencies Type#member might return a denotation that doesn't "really exists" (as defined by TypeAssigner#reallyExists), in some circumstance this denotation can refer to a symbol in a class that is in the classpath but that is not used by this file, so using addDependency on the result of Type#member might add a false dependency. We avoid this by using Type#select instead which will internally do the right thing. This issue was discovered while compiling the bootstrapped projects which would sometimes force a full recompilation for no reason. --- compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index fefa63f6fdc4..c392880c5cc8 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -175,7 +175,7 @@ private class ExtractDependenciesCollector(implicit val ctx: Context) extends tp override def traverse(tree: Tree)(implicit ctx: Context): Unit = { tree match { case Import(expr, selectors) => - def lookupImported(name: Name) = expr.tpe.member(name).symbol + def lookupImported(name: Name) = expr.tpe.select(name).typeSymbol def addImported(name: Name) = { // importing a name means importing both a term and a type (if they exist) addDependency(lookupImported(name.toTermName)) From 239a850f2d89a78e53386e3f9b8959be74bb9e65 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 11 Jan 2017 08:59:22 +0100 Subject: [PATCH 13/14] .drone.yml: Give more resources to the JVM used by sbt sbt runs up to `Runtime.getRuntime.availableProcessors` tasks in parallel, on our CI that means 40 tasks, compilation tasks are the one with the biggest footprint and the introduction of `dotty-library-bootstrapped` and `dotty-compiler-bootstrapped` in this PR means that sbt can now run more compilation tasks in parallel. To prevent the JVM from exploding, we increase: - The max heap size, from 1G to 4G - The max code cache size, from 240M to 512M - The max metaspace size, from 256M to 1G --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 96c5d0b54e8b..9e646262fe23 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ pipeline: commands: - ln -s /var/cache/drone/scala-scala scala-scala - ./scripts/update-scala-library - - sbt -Ddotty.drone.mem=4096m -ivy /var/cache/drone/ivy2 "${TEST}" + - sbt -J-Xmx4096m -J-XX:ReservedCodeCacheSize=512m -J-XX:MaxMetaspaceSize=1024m -Ddotty.drone.mem=4096m -ivy /var/cache/drone/ivy2 "${TEST}" matrix: TEST: From fc2f9314be7281e24e4ce7434f97cc42cb2f01d4 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 11 Jan 2017 13:42:02 +0100 Subject: [PATCH 14/14] Add meta project dotty-bootstrapped This way you can run both the dotty-library-bootstrapped and dotty-compiler-bootstrapped tests with one command: sbt ;publishLocal;dotty-bootstrapped/test --- .drone.yml | 2 +- project/Build.scala | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 9e646262fe23..16a5aff4993a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -10,6 +10,6 @@ pipeline: matrix: TEST: - test - - dotty-compiler-bootstrapped/test + - ;publishLocal;dotty-bootstrapped/test - partest-only-no-bootstrap --show-diff --verbose - partest-only --show-diff --verbose diff --git a/project/Build.scala b/project/Build.scala index a24fc5371ad5..7784926244ff 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -140,6 +140,12 @@ object DottyBuild extends Build { ). settings(publishing) + // Meta project aggregating all bootstrapped projects + lazy val `dotty-bootstrapped` = project. + aggregate(`dotty-library-bootstrapped`, `dotty-compiler-bootstrapped`). + settings( + publishArtifact := false + ) lazy val `dotty-interfaces` = project.in(file("interfaces")). settings(sourceStructure).