Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add partial Dotty support #74

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions backend/src/main/scala/bloop/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import xsbti.T2
import java.util.Optional
import java.io.File

import bloop.internal.Ecosystem
import bloop.io.{AbsolutePath, Paths}
import bloop.logging.Logger
import sbt.internal.inc.{FreshCompilerCache, Locate, LoggedReporter, ZincUtil}
Expand All @@ -23,7 +24,6 @@ case class CompileInputs(
)

object Compiler {

private final class ZincClasspathEntryLookup(previousResult: PreviousResult)
extends PerClasspathEntryLookup {
override def analysis(classpathEntry: File): Optional[CompileAnalysis] =
Expand Down Expand Up @@ -63,7 +63,9 @@ object Compiler {
val reporter = new LoggedReporter(100, compileInputs.logger)
val compilerCache = new FreshCompilerCache
val cacheFile = compileInputs.baseDirectory.resolve("cache").toFile
val incOptions = IncOptions.create()
val incOptions =
if (!compileInputs.scalaInstance.isDotty) IncOptions.create()
else Ecosystem.supportDotty(IncOptions.create())
val progress = Optional.empty[CompileProgress]
Setup.create(lookup, skip, cacheFile, compilerCache, incOptions, reporter, progress, empty)
}
Expand Down
4 changes: 4 additions & 0 deletions backend/src/main/scala/bloop/ScalaInstance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class ScalaInstance(
isJar(filename) && !hasScalaCompilerName(filename) && !hasScalaLibraryName(filename)
}

def isDotty: Boolean =
organization == "ch.epfl.lamp" && sbt.internal.inc.ScalaInstance.isDotty(version)

/** Tells us what the real version of the classloaded scalac compiler in this instance is. */
override def actualVersion(): String = {
// TODO: Report when the `actualVersion` and the passed in version do not match.
Expand Down Expand Up @@ -101,6 +104,7 @@ object ScalaInstance {
val localArtifacts: Seq[FileError \/ File] =
Task.gatherUnordered(resolution.artifacts.map(Cache.file(_).run)).unsafePerformSync
val allJars = localArtifacts.flatMap(_.toList).filter(_.getName.endsWith(".jar"))
println(allJars)
new ScalaInstance(scalaOrg, scalaName, scalaVersion, allJars.toArray)
}

Expand Down
45 changes: 45 additions & 0 deletions backend/src/main/scala/bloop/internal/Ecosystem.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package bloop.internal

import java.io.File
import java.util.Optional

import xsbti.compile.{
ClassFileManager,
ClassFileManagerUtil,
DefaultExternalHooks,
IncOptions,
WrappedClassFileManager
}

object Ecosystem {
def supportDotty(incOptions: IncOptions): IncOptions = {
val tastyFileManager = new ClassFileManager {
private[this] val inherited = ClassFileManagerUtil.getDefaultClassFileManager(incOptions)

def delete(classes: Array[File]): Unit = {
val tastySuffixes = List(".tasty", ".hasTasty")
inherited.delete(classes flatMap { classFile =>
if (classFile.getPath endsWith ".class") {
val prefix = classFile.getAbsolutePath.stripSuffix(".class")
tastySuffixes.map(suffix => new File(prefix + suffix)).filter(_.exists)
} else Nil
})
}

def generated(classes: Array[File]): Unit = {}
def complete(success: Boolean): Unit = {}
}
val inheritedHooks = incOptions.externalHooks
val externalClassFileManager: Optional[ClassFileManager] = Option(
inheritedHooks.getExternalClassFileManager.orElse(null)) match {
case Some(prevManager) =>
Optional.of(WrappedClassFileManager.of(prevManager, Optional.of(tastyFileManager)))
case None =>
Optional.of(tastyFileManager)
}

val newExternalHooks =
new DefaultExternalHooks(inheritedHooks.getExternalLookup, externalClassFileManager)
incOptions.withExternalHooks(newExternalHooks)
}
}
12 changes: 10 additions & 2 deletions backend/src/main/scala/sbt/internal/inc/bloop/ZincInternals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,23 @@ object ZincInternals {
def compilerBridgeId(scalaVersion: String) = {
// Defaults to bridge for 2.13 for Scala versions bigger than 2.13.x
scalaVersion match {
case sc if (sc startsWith "0.") => "dotty-sbt-bridge"
case sc if (sc startsWith "2.10.") => "compiler-bridge_2.10"
case sc if (sc startsWith "2.11.") => "compiler-bridge_2.11"
case sc if (sc startsWith "2.12.") => "compiler-bridge_2.12"
case _ => "compiler-bridge_2.13"
}
}

val bridgeId = compilerBridgeId(scalaInstance.version)
ModuleID("ch.epfl.scala", bridgeId, latestVersion).withConfigurations(CompileConf).sources()
val (organization, name, version) = {
val bridgeId = compilerBridgeId(scalaInstance.version)
println(scalaInstance)
println(scalaInstance.isDotty)
if (scalaInstance.isDotty) (scalaInstance.organization, bridgeId, scalaInstance.version)
else ("ch.epfl.scala", bridgeId, latestVersion)
}

ModuleID(organization, name, version).withConfigurations(CompileConf).sources()
}

/**
Expand Down
24 changes: 18 additions & 6 deletions frontend/src/test/scala/bloop/tasks/CompilationTaskTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ object CompilationTaskTest extends TestSuite {
val `B2.scala` = "package p1\ntrait B"
val `C.scala` = "package p2\nimport p0.A\nimport p1.B\nobject C extends A with B"
val `C2.scala` = "package p2\nimport p0.A\nobject C extends A"
val `Dotty.scala` = "package p0\nobject Foo { val x: String | Int = 1 }"
}

def checkAfterCleanCompilation(structures: Map[String, Map[String, String]],
dependencies: Map[String, Set[String]],
scalaInstance: ScalaInstance = CompilationHelpers.scalaInstance,
logger: Logger)(
afterCompile: Map[String, Project] => Unit = (_ => ())) = {
withProjects(structures, dependencies) { projects =>
def checkAfterCleanCompilation(
structures: Map[String, Map[String, String]],
dependencies: Map[String, Set[String]],
scalaInstance: ScalaInstance = CompilationHelpers.scalaInstance,
logger: Logger)(afterCompile: Map[String, Project] => Unit = (_ => ())) = {
withProjects(structures, dependencies, scalaInstance) { projects =>
// Check that this is a clean compile!
assert(projects.forall { case (_, prj) => noPreviousResult(prj) })
val project = projects(ProjectNameToCompile)
Expand Down Expand Up @@ -127,6 +128,17 @@ object CompilationTaskTest extends TestSuite {
}
}
}

"Compile one project with Dotty 0.4.0-RC1" - {
val scalaInstance = ScalaInstance.resolve("ch.epfl.lamp", "dotty-compiler_0.4", "0.4.0-RC1")
logger.quietIfSuccess { logger =>
val ps = Map(ProjectNameToCompile -> Map("Dotty.scala" -> ArtificialSources.`Dotty.scala`))
checkAfterCleanCompilation(ps, Map.empty, scalaInstance = scalaInstance, logger = logger) {
(projects: Map[String, Project]) =>
assert(projects.forall { case (_, prj) => hasPreviousResult(prj) })
}
}
}
}

private def simpleProject(scalaInstance: ScalaInstance, logger: Logger): Unit = {
Expand Down