Skip to content

Commit

Permalink
Merge branch '1.0.x' into merge-1.0.x-into-1.x
Browse files Browse the repository at this point in the history
* 1.0.x: (28 commits)
  Split compiler bridge tests to another subproject
  Implement compiler bridge for 2.13.0-M2
  Add yourkit acknoledgement in the README
  "sbt '++ 2.13.0-M2!' compile" does not work with sbt 1.0.0
  Add header to cached hashing spec
  Add headers to missing files
  Fix #332: Add sbt-header back to the build
  Update sbt-scalafmt to 1.12
  Make classpath hashing more lightweight
  Fix #442: Name hash of value class should include underlying type
  source-dependencies/value-class-underlying: fix test
  Ignore null in generic lambda tparams
  Improve and make scripted parallel
  Fix #436: Remove annoying log4j scripted exception
  Fix #127: Use `unexpanded` name instead of `name`
  Add pending test case for issue/127
  source-dependencies / patMat-scope workaround
  Fixes undercompilation on inheritance on same source
  Add real reproduction case for #417
  Add trait-trait-212 for Scala 2.12.3
  ...

 Conflicts:
	internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala
	project/build.properties
	zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala

The ClassToAPI conflict is due to:
* #393 (a 1.x PR), conflicting with
* #446 (a 1.0.x PR).

The build.properties conflict is due to different PRs bumping
sbt.version from 1.0.0 to 1.0.2 to 1.0.3. (#413, #418, #453).

The MixedAnalyzingCompiler conflict is due to:
* #427 (a 1.x PR), conflicting with
* #452 (a 1.0.x PR).
  • Loading branch information
dwijnand committed Nov 23, 2017
2 parents b1e7eac + d6d6988 commit e245d95
Show file tree
Hide file tree
Showing 96 changed files with 1,235 additions and 120 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,9 @@ active development. For information on how to contribute, please check the
[CONTRIBUTING guide](CONTRIBUTING.md).

This software is released under the following [LICENSE](LICENSE).

## Acknoledgements

| Logo | Acknoledgement |
| ---- | -------------- |
| ![](https://www.yourkit.com/images/yklogo.png) | We thank [Yourkit](https://www.yourkit.com/) for supporting this open-source project with its full-featured profiler. |
43 changes: 43 additions & 0 deletions bin/bridge213.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

# This is a hack to validate the compilation of 2.13 compiler bridge without using sbt,
# which was used for bootstrapping the initial compiler bridge.
# In the future when Scala compiler breaks source compatibility, this script might come in handy.

# $ export SCALA_X_HOME=/usr/local/Cellar/scala@2.13/2.13.0-M2

if [[ -z "$SCALA_X_HOME" ]]; then
echo "SCALA_X_HOME is not set!" 1>&2
echo "Run 'export SCALA_X_HOME=/usr/local/Cellar/scala@2.13/2.13.0-M2' or equivalent."
exit 1
fi

mkdir -p target/compiler-bridge/

"$SCALA_X_HOME/bin/scalac" \
-nowarn \
-classpath $HOME/.ivy2/cache/org.scala-sbt/compiler-interface/jars/compiler-interface-1.0.3.jar:$HOME/.ivy2/cache/org.scala-sbt/util-interface/jars/util-interface-1.0.2.jar \
-d target/compiler-bridge/ \
internal/compiler-bridge/src/main/scala/xsbt/API.scala \
internal/compiler-bridge/src/main/scala/xsbt/DelegatingReporter.scala \
internal/compiler-bridge/src/main/scala/xsbt/InteractiveConsoleInterface.scala \
internal/compiler-bridge/src/main/scala/xsbt/ScaladocInterface.scala \
internal/compiler-bridge/src/main/scala/xsbt/Analyzer.scala \
internal/compiler-bridge/src/main/scala/xsbt/Dependency.scala \
internal/compiler-bridge/src/main/scala/xsbt/InteractiveConsoleResponse.scala \
internal/compiler-bridge/src/main/scala/xsbt/CallbackGlobal.scala \
internal/compiler-bridge/src/main/scala/xsbt/ExtractAPI.scala \
internal/compiler-bridge/src/main/scala/xsbt/JavaUtils.scala \
internal/compiler-bridge/src/main/scala/xsbt/ClassName.scala \
internal/compiler-bridge/src/main/scala/xsbt/ExtractUsedNames.scala \
internal/compiler-bridge/src/main/scala/xsbt/LocalToNonLocalClass.scala \
internal/compiler-bridge/src/main/scala/xsbt/Command.scala \
internal/compiler-bridge/src/main/scala/xsbt/GlobalHelpers.scala \
internal/compiler-bridge/src/main/scala/xsbt/LocateClassFile.scala \
internal/compiler-bridge/src/main/scala/xsbt/CompilerInterface.scala \
internal/compiler-bridge/src/main/scala/xsbt/InteractiveConsoleFactory.scala \
internal/compiler-bridge/src/main/scala/xsbt/Log.scala \
internal/compiler-bridge/src/main/scala/xsbt/InteractiveConsoleHelper.scala \
internal/compiler-bridge/src/main/scala/xsbt/Message.scala \
internal/compiler-bridge/src/main/scala_2.13/xsbt/Compat.scala \
internal/compiler-bridge/src/main/scala_2.13/xsbt/ConsoleInterface.scala
File renamed without changes.
3 changes: 2 additions & 1 deletion bin/run-ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ sbt -Dfile.encoding=UTF-8 \
-J-XX:ReservedCodeCacheSize=256M \
-J-Xmx3046M -J-Xms3046M -J-server \
+mimaReportBinaryIssues \
scalafmtTest \
scalafmt::test \
test:scalafmt::test \
zincRoot/test:compile \
crossTestBridges \
"publishBridgesAndSet $SCALA_VERSION" \
Expand Down
77 changes: 55 additions & 22 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Util._
import Dependencies._
import Scripted._
//import com.typesafe.tools.mima.core._, ProblemFilters._

def baseVersion = "1.1.0-SNAPSHOT"
def internalPath = file("internal")

lazy val compilerBridgeScalaVersions = List(scala212, scala211, scala210)
lazy val compilerBridgeScalaVersions = List(scala212, scala213, scala211, scala210)
lazy val compilerBridgeTestScalaVersions = List(scala212, scala211, scala210)

def mimaSettings: Seq[Setting[_]] = Seq(
mimaPreviousArtifacts := Set(
Expand Down Expand Up @@ -157,6 +157,9 @@ lazy val zincRoot: Project = (project in file("."))
homepage := Some(url("https://github.com/sbt/zinc")),
developers +=
Developer("jvican", "Jorge Vicente Cantero", "@jvican", url("https://github.com/jvican")),
scalafmtOnCompile := true,
scalafmtVersion := "1.2.0",
scalafmtOnCompile in Sbt := false,
)),
minimalSettings,
otherRootSettings,
Expand Down Expand Up @@ -328,10 +331,17 @@ def wrapIn(color: String, content: String): String = {
else color + content + scala.Console.RESET
}

// Compiler-side interface to compiler that is compiled against the compiler being used either in advance or on the fly.
// Includes API and Analyzer phases that extract source API and relationships.
/**
* Compiler-side interface to compiler that is compiled against the compiler being used either in advance or on the fly.
* Includes API and Analyzer phases that extract source API and relationships.
* As this is essentially implementations of the compiler-interface (per Scala compiler),
* the code here should not be consumed without going through the classloader trick and the interface.
* Due to the hermetic nature of the bridge, there's no necessity to keep binary compatibility across Zinc versions,
* and therefore there's no `mimaSettings` added.
* For the case of Scala 2.13 bridge, we didn't even have the bridge to compare against when Zinc 1.0.0 came out.
*/
lazy val compilerBridge: Project = (project in internalPath / "compiler-bridge")
.dependsOn(compilerInterface % "compile;test->test", zincApiInfo % "test->test")
.dependsOn(compilerInterface)
.settings(
baseSettings,
crossScalaVersions := compilerBridgeScalaVersions,
Expand All @@ -341,17 +351,19 @@ lazy val compilerBridge: Project = (project in internalPath / "compiler-bridge")
// precompiledSettings,
name := "Compiler Bridge",
exportJars := true,
// we need to fork because in unit tests we set usejavacp = true which means
// we are expecting all of our dependencies to be on classpath so Scala compiler
// can use them while constructing its own classpath for compilation
fork in Test := true,
// needed because we fork tests and tests are ran in parallel so we have multiple Scala
// compiler instances that are memory hungry
javaOptions in Test += "-Xmx1G",
inBoth(unmanagedSourceDirectories ++= scalaPartialVersion.value.collect {
case (2, y) if y == 10 => new File(scalaSource.value.getPath + "_2.10")
case (2, y) if y >= 11 => new File(scalaSource.value.getPath + "_2.11+")
case (2, y) if y == 10 => new File(scalaSource.value.getPath + "_2.10")
case (2, y) if y == 11 || y == 12 => new File(scalaSource.value.getPath + "_2.11-12")
case (2, y) if y >= 13 => new File(scalaSource.value.getPath + "_2.13")
}.toList),
// Use a bootstrap compiler bridge to compile the compiler bridge.
scalaCompilerBridgeSource := {
val old = scalaCompilerBridgeSource.value
scalaVersion.value match {
case x if x startsWith "2.13." => ("org.scala-sbt" % "compiler-bridge_2.13.0-M2" % "1.1.0-M1-bootstrap2" % Compile).sources()
case _ => old
}
},
cleanSbtBridge := {
val sbtV = sbtVersion.value
val sbtOrg = "org.scala-sbt"
Expand Down Expand Up @@ -383,7 +395,30 @@ lazy val compilerBridge: Project = (project in internalPath / "compiler-bridge")
},
publishLocal := publishLocal.dependsOn(cleanSbtBridge).value,
altPublishSettings,
mimaSettings,
)

/**
* Tests for the compiler bridge.
* This is split into a separate subproject because testing introduces more dependencies
* (Zinc API Info, which transitively depends on IO).
*/
lazy val compilerBridgeTest = (project in internalPath / "compiler-bridge-test")
.dependsOn(compilerBridge, compilerInterface % "test->test", zincApiInfo % "test->test")
.settings(
name := "Compiler Bridge Test",
baseSettings,
relaxNon212,
// we need to fork because in unit tests we set usejavacp = true which means
// we are expecting all of our dependencies to be on classpath so Scala compiler
// can use them while constructing its own classpath for compilation
fork in Test := true,
// needed because we fork tests and tests are ran in parallel so we have multiple Scala
// compiler instances that are memory hungry
javaOptions in Test += "-Xmx1G",
crossScalaVersions := compilerBridgeTestScalaVersions,
libraryDependencies += scalaCompiler.value,
altPublishSettings,
skip in publish := true,
)

val scalaPartialVersion = Def setting (CrossVersion partialVersion scalaVersion.value)
Expand All @@ -397,7 +432,7 @@ lazy val zincApiInfo = (project in internalPath / "zinc-apiinfo")
.configure(addBaseSettingsAndTestDeps)
.settings(
name := "zinc ApiInfo",
crossScalaVersions := compilerBridgeScalaVersions,
crossScalaVersions := compilerBridgeTestScalaVersions,
relaxNon212,
mimaSettings,
)
Expand All @@ -408,7 +443,7 @@ lazy val zincClasspath = (project in internalPath / "zinc-classpath")
.configure(addBaseSettingsAndTestDeps)
.settings(
name := "zinc Classpath",
crossScalaVersions := compilerBridgeScalaVersions,
crossScalaVersions := compilerBridgeTestScalaVersions,
relaxNon212,
libraryDependencies ++= Seq(scalaCompiler.value, launcherInterface),
mimaSettings,
Expand All @@ -421,7 +456,7 @@ lazy val zincClassfile = (project in internalPath / "zinc-classfile")
.configure(addBaseSettingsAndTestDeps)
.settings(
name := "zinc Classfile",
crossScalaVersions := compilerBridgeScalaVersions,
crossScalaVersions := compilerBridgeTestScalaVersions,
relaxNon212,
mimaSettings,
)
Expand All @@ -439,10 +474,10 @@ lazy val zincScripted = (project in internalPath / "zinc-scripted")

lazy val crossTestBridges = {
Command.command("crossTestBridges") { state =>
(compilerBridgeScalaVersions.flatMap { (bridgeVersion: String) =>
(compilerBridgeTestScalaVersions.flatMap { (bridgeVersion: String) =>
// Note the ! here. You need this so compilerInterface gets forced to the scalaVersion
s"++ $bridgeVersion!" ::
s"${compilerBridge.id}/test" ::
s"${compilerBridgeTest.id}/test" ::
Nil
}) :::
(s"++ $scala212!" ::
Expand All @@ -457,7 +492,6 @@ lazy val publishBridgesAndSet = {
s"${compilerInterface.id}/publishLocal" ::
compilerBridgeScalaVersions.flatMap { (bridgeVersion: String) =>
s"++ $bridgeVersion!" ::
s"${zincApiInfo.id}/publishLocal" ::
s"${compilerBridge.id}/publishLocal" :: Nil
} :::
s"++ $userScalaVersion!" ::
Expand All @@ -473,7 +507,6 @@ lazy val publishBridgesAndTest = Command.args("publishBridgesAndTest", "<version
s"${compilerInterface.id}/publishLocal" ::
(compilerBridgeScalaVersions.flatMap { (bridgeVersion: String) =>
s"++ $bridgeVersion" ::
s"${zincApiInfo.id}/publishLocal" ::
s"${compilerBridge.id}/publishLocal" :: Nil
}) :::
s"++ $version" ::
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# xsbti Java interfaces must be defined in the compiler interface, not the bridge.
# Bridge implementations are compiled per Zinc, so these are safe to change.
ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleFactory")
ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleResult")
ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleInterface")
ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleResponse")
8 changes: 6 additions & 2 deletions internal/compiler-bridge/src/main/scala/xsbt/ClassName.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,19 @@ trait ClassName extends Compat {
*
* If `s` represents a package object `pkg3`, then the returned name will be `pkg1.pkg2.pkg3.package`.
* If `s` represents a class `Foo` nested in package object `pkg3` then the returned name is `pkg1.pkg2.pk3.Foo`.
*
* Note that some objects with special access rights are encoded in names
* (like qualified privates `private[qualifier]`). In order to get the right
* original names, we need to use `unexpandedName`.
*/
protected def classNameAsSeenIn(in: Symbol, s: Symbol): String =
enteringPhase(currentRun.picklerPhase.next) {
if (in.isRoot || in.isRootPackage || in == NoSymbol || in.isEffectiveRoot)
s.simpleName.toString
else if (in.isPackageObjectOrClass)
in.owner.fullName + "." + s.name
in.owner.fullName + "." + s.unexpandedName
else
in.fullName + "." + s.name
in.fullName + "." + s.unexpandedName
}

private def pickledName(s: Symbol): Name =
Expand Down
21 changes: 13 additions & 8 deletions internal/compiler-bridge/src/main/scala/xsbt/Dependency.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,21 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile with
}

// Define processor reusing `processDependency` definition
val memberRef = processDependency(DependencyByMemberRef) _
val inheritance = processDependency(DependencyByInheritance) _
val localInheritance = processDependency(LocalDependencyByInheritance) _
val memberRef = processDependency(DependencyByMemberRef, false) _
val inheritance = processDependency(DependencyByInheritance, true) _
val localInheritance = processDependency(LocalDependencyByInheritance, true) _

@deprecated("Use processDependency that takes allowLocal.", "1.1.0")
def processDependency(context: DependencyContext)(dep: ClassDependency): Unit =
processDependency(context, true)(dep)

/*
* Handles dependency on given symbol by trying to figure out if represents a term
* that is coming from either source code (not necessarily compiled in this compilation
* run) or from class file and calls respective callback method.
*/
def processDependency(context: DependencyContext)(dep: ClassDependency): Unit = {
def processDependency(context: DependencyContext, allowLocal: Boolean)(
dep: ClassDependency): Unit = {
val fromClassName = classNameAsString(dep.from)

def binaryDependency(file: File, binaryClassName: String) =
Expand Down Expand Up @@ -134,11 +139,12 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile with
case None =>
debuglog(Feedback.noOriginFileForExternalSymbol(dep.to))
}
} else if (onSource.file != sourceFile) {
// Dependency is internal -- but from other file / compilation unit
} else if (onSource.file != sourceFile || allowLocal) {
// We cannot ignore dependencies coming from the same source file because
// the dependency info needs to propagate. See source-dependencies/trait-trait-211.
val onClassName = classNameAsString(dep.to)
callback.classDependency(onClassName, fromClassName, context)
} else () // Comes from the same file, ignore
}
}
}

Expand Down Expand Up @@ -228,7 +234,6 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile with
val depClass = enclOrModuleClass(dep)
val dependency = ClassDependency(fromClass, depClass)
if (!cache.contains(dependency) &&
fromClass.associatedFile != depClass.associatedFile &&
!depClass.isRefinementClass) {
process(dependency)
cache.add(dependency)
Expand Down
11 changes: 10 additions & 1 deletion internal/compiler-bridge/src/main/scala/xsbt/ExtractAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,16 @@ class ExtractAPI[GlobalType <: Global](
* TODO: can we include hashes for parent classes instead? This seems a bit messy.
*/
private def mkStructureWithInherited(info: Type, s: Symbol): xsbti.api.Structure = {
val ancestorTypes = linearizedAncestorTypes(info)
val ancestorTypes0 = linearizedAncestorTypes(info)
val ancestorTypes =
if (s.isDerivedValueClass) {
val underlying = s.derivedValueClassUnbox.tpe.finalResultType
// The underlying type of a value class should be part of the name hash
// of the value class (see the test `value-class-underlying`), this is accomplished
// by adding the underlying type to the list of parent types.
underlying :: ancestorTypes0
} else
ancestorTypes0
val decls = info.decls.toList
val declsNoModuleCtor = if (s.isModuleClass) removeConstructors(decls) else decls
val declSet = decls.toSet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

package xsbt

import scala.tools.nsc.interpreter.IR
import Compat._
import xsbti.InteractiveConsoleResult

object InteractiveConsoleHelper {
implicit def toConsoleResult(ir: IR.Result): InteractiveConsoleResult =
implicit def toConsoleResult(ir: Results.Result): InteractiveConsoleResult =
ir match {
case IR.Success => InteractiveConsoleResult.Success
case IR.Incomplete => InteractiveConsoleResult.Incomplete
case IR.Error => InteractiveConsoleResult.Error
case Results.Success => InteractiveConsoleResult.Success
case Results.Incomplete => InteractiveConsoleResult.Incomplete
case Results.Error => InteractiveConsoleResult.Error
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import scala.tools.nsc.{ GenericRunnerCommand, Settings }

import xsbti.Logger

import Compat._
import InteractiveConsoleHelper._

class InteractiveConsoleInterface(
Expand All @@ -38,9 +39,10 @@ class InteractiveConsoleInterface(
val outWriter: StringWriter = new StringWriter
val poutWriter: PrintWriter = new PrintWriter(outWriter)

val interpreter: IMain = new IMain(compilerSettings, new PrintWriter(outWriter)) {
def lastReq: Request = prevRequestList.last
}
val interpreter: IMain =
new IMain(compilerSettings, replReporter(compilerSettings, new PrintWriter(outWriter))) {
def lastReq: Request = prevRequestList.last
}

def interpret(line: String, synthetic: Boolean): InteractiveConsoleResponse = {
clearBuffer()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package xsbt

import java.io.PrintWriter
import xsbti.compile.Output
import scala.reflect.{ internal => sri }
import scala.reflect.internal.{ util => sriu }
Expand Down Expand Up @@ -150,6 +151,12 @@ trait ZincGlobalCompat {
}

object Compat {
// IR is renamed to Results
val Results = scala.tools.nsc.interpreter.IR

// IMain in 2.13 accepts ReplReporter
def replReporter(settings: Settings, writer: PrintWriter) = writer

implicit final class TreeOps(val tree: sri.Trees#Tree) extends AnyVal {
// Introduced in 2.11
@inline final def hasSymbolField: Boolean = tree.hasSymbol
Expand Down
Loading

0 comments on commit e245d95

Please sign in to comment.