From b5b07348f0189491ae6be3c2f57ddfbd04665535 Mon Sep 17 00:00:00 2001 From: Martin Duhem Date: Sun, 16 Mar 2014 16:35:39 +0100 Subject: [PATCH 1/2] Add a pending test for sbt/sbt#1142 Add a scripted test documents the current behavior of incremental compiler when it comes to handling of inherited macros. A whitespace change to a file that inherits a macro triggers recompilation of all files that depend (by composition or inheritance) on that file. --- .../inherited-macros/changes/Client.scala | 7 +++++ .../inherited-macros/macro-client/build.sbt | 9 ++++++ .../macro-client/src/main/scala/Client.scala | 7 +++++ .../macro-client/src/main/scala/Foo.scala | 5 ++++ .../src/main/scala/Provider.scala | 7 +++++ .../inherited-macros/pending | 12 ++++++++ .../inherited-macros/project/build.scala | 29 +++++++++++++++++++ 7 files changed, 76 insertions(+) create mode 100644 sbt/src/sbt-test/source-dependencies/inherited-macros/changes/Client.scala create mode 100644 sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/build.sbt create mode 100644 sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Client.scala create mode 100644 sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Foo.scala create mode 100644 sbt/src/sbt-test/source-dependencies/inherited-macros/macro-provider/src/main/scala/Provider.scala create mode 100644 sbt/src/sbt-test/source-dependencies/inherited-macros/pending create mode 100644 sbt/src/sbt-test/source-dependencies/inherited-macros/project/build.scala diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/changes/Client.scala b/sbt/src/sbt-test/source-dependencies/inherited-macros/changes/Client.scala new file mode 100644 index 000000000..19633db64 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/inherited-macros/changes/Client.scala @@ -0,0 +1,7 @@ +package macro + +object Client { + object RealClient extends Provider { + // Some comment... + } +} diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/build.sbt b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/build.sbt new file mode 100644 index 000000000..75588e23c --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/build.sbt @@ -0,0 +1,9 @@ +// Check that a file has not been recompiled during last compilation +InputKey[Unit]("check-not-recompiled") <<= inputTask { (argTask: TaskKey[Seq[String]]) => + (argTask, compile in Compile) map { (args: Seq[String], a: sbt.inc.Analysis) => + assert(args.size == 1) + val fileCompilation = a.apis.internal.collect { case (file, src) if file.name.endsWith(args(0)) => src.compilation }.head + val lastCompilation = a.compilations.allCompilations.last + assert(fileCompilation.startTime != lastCompilation.startTime, "File has been recompiled during last compilation.") + } +} \ No newline at end of file diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Client.scala b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Client.scala new file mode 100644 index 000000000..6351461a7 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Client.scala @@ -0,0 +1,7 @@ +package macro + +object Client { + object RealClient extends Provider { + + } +} diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Foo.scala b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Foo.scala new file mode 100644 index 000000000..be7a40427 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-client/src/main/scala/Foo.scala @@ -0,0 +1,5 @@ +package macro + +object Foo { + val c = Client.RealClient +} diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-provider/src/main/scala/Provider.scala b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-provider/src/main/scala/Provider.scala new file mode 100644 index 000000000..14523f149 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/inherited-macros/macro-provider/src/main/scala/Provider.scala @@ -0,0 +1,7 @@ +package macro +import scala.language.experimental.macros +import scala.reflect.macros._ + +abstract class Provider { + def notImplementedMacro = macro ??? +} diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/pending b/sbt/src/sbt-test/source-dependencies/inherited-macros/pending new file mode 100644 index 000000000..9a6e7dfcf --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/inherited-macros/pending @@ -0,0 +1,12 @@ +> macro-provider/compile + +> macro-client/compile + +# Introduce a comment in Client, which inherits a macro from Provider +$ copy-file changes/Client.scala macro-client/src/main/scala/Client.scala + +> macro-client/compile + +# Object Foo depends on Client via composition, thus a whitespace change to +# Client shouldn't trigger its recompilation +> check-not-recompiled Foo.scala diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/project/build.scala b/sbt/src/sbt-test/source-dependencies/inherited-macros/project/build.scala new file mode 100644 index 000000000..27a684ef8 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/inherited-macros/project/build.scala @@ -0,0 +1,29 @@ +import sbt._ +import Keys._ + +object build extends Build { + val defaultSettings = Seq( + libraryDependencies <+= scalaVersion("org.scala-lang" % "scala-reflect" % _ )//, + //incOptions := incOptions.value.withNameHashing(true) + ) + + lazy val root = Project( + base = file("."), + id = "macro", + aggregate = Seq(macroProvider, macroClient), + settings = Defaults.defaultSettings ++ defaultSettings + ) + + lazy val macroProvider = Project( + base = file("macro-provider"), + id = "macro-provider", + settings = Defaults.defaultSettings ++ defaultSettings + ) + + lazy val macroClient = Project( + base = file("macro-client"), + id = "macro-client", + dependencies = Seq(macroProvider), + settings = Defaults.defaultSettings ++ defaultSettings + ) +} From 5a40641cc158e370026df263fcdd124f09c6c574 Mon Sep 17 00:00:00 2001 From: Martin Duhem Date: Sun, 16 Mar 2014 17:09:02 +0100 Subject: [PATCH 2/2] Classes that only inherit a macro don't have a macro Prior to this commit, a class that inherited a macro from another class was considered by incremental compiler as having a macro. Now, only classes that explicitly define a macro are considered as having a macro. This influences decision whether to invalidate (recompile) dependencies of a file that inherits a macro upon a whitespace change. From now on, we don't invalidate dependencies in such case which results in much better incremental compiler experience when macros are being involved. Check #1142 for detailed discussion. The change to the behavior is reflected by marking the source-dependencies/inherited-macros test as passing. The source-dependencies/macro test covers the case of defining the macro directly in source file. Therefore we know that the desired behavior of invalidating dependencies of macros is preserved. Fixes #1142 --- compile/api/src/main/scala/xsbt/api/APIUtil.scala | 8 ++++++++ .../inherited-macros/{pending => test} | 0 2 files changed, 8 insertions(+) rename sbt/src/sbt-test/source-dependencies/inherited-macros/{pending => test} (100%) diff --git a/compile/api/src/main/scala/xsbt/api/APIUtil.scala b/compile/api/src/main/scala/xsbt/api/APIUtil.scala index 96892f3d8..50d287fe4 100644 --- a/compile/api/src/main/scala/xsbt/api/APIUtil.scala +++ b/compile/api/src/main/scala/xsbt/api/APIUtil.scala @@ -29,6 +29,14 @@ object APIUtil { var hasMacro = false + // Don't visit inherited definitions since we consider that a class + // that inherits a macro does not have a macro. + override def visitStructure0(structure: Structure) + { + visitTypes(structure.parents) + visitDefinitions(structure.declared) + } + override def visitModifiers(m: Modifiers) { hasMacro ||= m.isMacro diff --git a/sbt/src/sbt-test/source-dependencies/inherited-macros/pending b/sbt/src/sbt-test/source-dependencies/inherited-macros/test similarity index 100% rename from sbt/src/sbt-test/source-dependencies/inherited-macros/pending rename to sbt/src/sbt-test/source-dependencies/inherited-macros/test