Skip to content

Commit

Permalink
Merge pull request #123 from szeiger/wip/scala-2.12
Browse files Browse the repository at this point in the history
Add Scala 2.12 support
  • Loading branch information
szeiger authored Sep 29, 2016
2 parents 534198e + 807b940 commit 7c956c5
Show file tree
Hide file tree
Showing 23 changed files with 39 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ env:
- TEST_COMMAND="scripted"
- TEST_COMMAND="testFunctional"
- TEST_COMMAND="-Dmima.testScalaVersion=2.11.7 testFunctional"
- TEST_COMMAND="-Dmima.testScalaVersion=2.12.0-M3 testFunctional"
- TEST_COMMAND="-Dmima.testScalaVersion=2.12.0-RC1 testFunctional"

script:
- sbt -J-XX:ReservedCodeCacheSize=256M $TEST_COMMAND
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ After doing that, `reload` if you are in a `sbt` console session (if that makes

Tests within the `functional-tests` folder should always pass.

Note: The `problems.txt` is the test oracle. Expected errors are declared using the MiMa's reporting output (i.e., the output of the tool and the expected errors should match perfectly). Admittedly, this coupling is an issue since the testing framework is highly coupled with the tool output used to report errors to the user. We should improve this and make the two independent. Until then, mind that by changing the output of the tool you will likely have to update some of the test oracles (i.e., problems.txt file).
Note: The `problems.txt` is the test oracle. Expected errors are declared using the MiMa's reporting output (i.e., the output of the tool and the expected errors should match perfectly). Admittedly, this coupling is an issue since the testing framework is highly coupled with the tool output used to report errors to the user. We should improve this and make the two independent. Until then, mind that by changing the output of the tool you will likely have to update some of the test oracles (i.e., problems.txt file). When running tests against Scala 2.12 or higher, `problems-2.12.txt` is preferred over `problems.txt` if the former exists.

FAQ
-------
Expand Down
11 changes: 9 additions & 2 deletions core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,18 @@ abstract class ClassInfo(val owner: PackageInfo) extends HasDeclarationName with

/** The concrete methods of this trait */
lazy val concreteMethods: List[MemberInfo] = {
if(isTrait) methods.iterator.filter(hasStaticImpl(_)).toList
else if(isClass) methods.iterator.filter(!_.isDeferred).toList
if(isTrait) methods.iterator.filter(m => hasStaticImpl(m) || !m.isDeferred).toList
else if(isClass || isInterface) methods.iterator.filter(!_.isDeferred).toList
else Nil
}

/** The subset of concrete methods of this trait that are abstract at the JVM level.
* This corresponds to the pre-Scala-2.12 trait encoding where all `concreteMethods`
* are `emulatedConcreteMethods`. In 2.12 most concrete trait methods are translated
* to concrete interface methods. */
lazy val emulatedConcreteMethods: List[MemberInfo] =
concreteMethods.filter(_.isDeferred)

/** The deferred methods of this trait */
lazy val deferredMethods: List[MemberInfo] = {
val concreteSet = concreteMethods.toSet
Expand Down
14 changes: 10 additions & 4 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,11 @@ object MimaBuild extends Build {
lazy val runTest =
(fullClasspath in (reporterFunctionalTests, Compile), // the test classpath from the functionalTest project for the test
thisProjectRef, // gives us the ProjectRef this task is defined in
scalaInstance, // get a reference to the already loaded Scala classes so we get the advantage of a warm jvm
scalaInstance in core, // get a reference to the already loaded Scala classes so we get the advantage of a warm jvm
packageBin in v1Config, // package the v1 sources and get the configuration used
packageBin in v2Config, // same for v2
streams) map { (cp, proj, si, v1, v2, streams) =>
scalaVersion,
streams) map { (cp, proj, si, v1, v2, scalaV, streams) =>
val urls = Attributed.data(cp).map(_.toURI.toURL).toArray
val loader = new java.net.URLClassLoader(urls, si.loader)

Expand All @@ -238,9 +239,14 @@ object MimaBuild extends Build {

val projectPath = proj.build.getPath + "reporter" + "/" + "functional-tests" + "/" + "src" + "/" + "test" + "/" + proj.project

val oraclePath = projectPath + "/problems.txt"
val oraclePath = {
val p = projectPath + "/problems.txt"
val p212 = projectPath + "/problems-2.12.txt"
if(!(scalaV.startsWith("2.10.") || scalaV.startsWith("2.11.")) && new java.io.File(p212).exists) p212
else p
}

try {
try {
import scala.language.reflectiveCalls
testRunner.runTest(testClasspath, proj.project, v1.getAbsolutePath, v2.getAbsolutePath, oraclePath)
streams.log.info("Test '" + proj.project + "' succeeded.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declaration of class A is interface A in new version; changing class to interface breaks client code
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
in new version there is abstract method foo()Int in class B, which does not have a correspondent
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
method foo()Int in interface B does not have a correspondent in new version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
abstract synthetic method A$_setter_$foo_=(Int)Unit in interface A is present only in new version
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
abstract synthetic method A$_setter_|_=(Int)Unit in interface A is present only in new version
abstract method bar()Int in interface A is present only in new version
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
abstract method bar_=(Int)Unit in interface A is present only in new version
abstract method bar()Int in interface A is present only in new version
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
abstract method foo(Int)Int in interface A does not have a correspondent in new version
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
abstract method foo()Int in interface AA is inherited by class A in new version.
abstract synthetic method AA$_setter_|_=(Int)Unit in interface AA is inherited by class A in new version.
abstract method bar()Int in interface AA is inherited by class A in new version.
abstract method foo()Int in interface AA is inherited by class B in new version.
abstract synthetic method AA$_setter_|_=(Int)Unit in interface AA is inherited by class B in new version.
abstract method bar()Int in interface AA is inherited by class B in new version.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
method foo()Int in interface A does not have a correspondent in new version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
method foo()Int in interface A does not have a correspondent in new version
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ private[analyze] class TraitAnalyzer extends Analyzer {
override def analyzeNewClassMethods(oldclazz: ClassInfo, newclazz: ClassInfo): List[Problem] = {
val res = collection.mutable.ListBuffer.empty[Problem]

for (newmeth <- newclazz.concreteMethods if !oldclazz.hasStaticImpl(newmeth)) {
for (newmeth <- newclazz.emulatedConcreteMethods if !oldclazz.hasStaticImpl(newmeth)) {
if (!oldclazz.lookupMethods(newmeth.bytecodeName).exists(_.sig == newmeth.sig)) {
// this means that the method is brand new and therefore the implementation
// has to be injected
Expand Down

0 comments on commit 7c956c5

Please sign in to comment.