From 83075a90f5c5549fd5b70cdd24d42f903f1832dc Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 7 Jul 2016 19:33:47 +0100 Subject: [PATCH] Fixes #2654 Silence macro recompilation info message As well as add a test for the macro recompilation info message feature. --- .../src/main/scala/sbt/inc/IncOptions.scala | 49 +++++++++++++------ .../sbt/inc/IncrementalNameHashing.scala | 2 +- .../scala/sbt/inc/MemberRefInvalidator.scala | 4 +- notes/0.13.12.markdown | 3 +- .../macro-log/Client.scala | 7 +++ .../source-dependencies/macro-log/build.sbt | 19 +++++++ .../macro-log/macros/Bar.scala | 13 +++++ .../macro-log/macros/Baz.scala | 13 +++++ .../macro-log/macros/Foo.scala | 13 +++++ .../macro-log/macros/changes/Bar.scala | 13 +++++ .../macro-log/macros/changes/Baz.scala | 13 +++++ .../macro-log/macros/changes/Foo.scala | 13 +++++ .../source-dependencies/macro-log/test | 18 +++++++ 13 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/Client.scala create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/build.sbt create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/macros/Bar.scala create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/macros/Baz.scala create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/macros/Foo.scala create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Bar.scala create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Baz.scala create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Foo.scala create mode 100644 sbt/src/sbt-test/source-dependencies/macro-log/test diff --git a/compile/inc/src/main/scala/sbt/inc/IncOptions.scala b/compile/inc/src/main/scala/sbt/inc/IncOptions.scala index 17b65d65f..40ee0e4cc 100644 --- a/compile/inc/src/main/scala/sbt/inc/IncOptions.scala +++ b/compile/inc/src/main/scala/sbt/inc/IncOptions.scala @@ -84,7 +84,9 @@ final class IncOptions( /** * Include synthetic methods into the dependency tracking by name hashing. */ - val includeSynthToNameHashing: Boolean) extends Product with Serializable { + val includeSynthToNameHashing: Boolean, + /** Determines whether to log information on file recompiled due to a transitive macro change */ + val logRecompileOnMacro: Boolean) extends Product with Serializable { /** * Secondary constructor introduced to make IncOptions to be binary compatible with version that didn't have @@ -94,7 +96,8 @@ final class IncOptions( apiDiffContextSize: Int, apiDumpDirectory: Option[java.io.File], newClassfileManager: () => ClassfileManager) = { this(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, apiDumpDirectory, newClassfileManager, IncOptions.recompileOnMacroDefDefault, IncOptions.nameHashingDefault, - IncOptions.antStyleDefault, IncOptions.includeSynthToNameHashingDefault) + IncOptions.antStyleDefault, IncOptions.includeSynthToNameHashingDefault, + IncOptions.logRecompileOnMacroDefault) } def this(transitiveStep: Int, recompileAllFraction: Double, relationsDebug: Boolean, apiDebug: Boolean, @@ -102,64 +105,81 @@ final class IncOptions( recompileOnMacroDef: Boolean, nameHashing: Boolean, antStyle: Boolean) = { this(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, - antStyle, IncOptions.includeSynthToNameHashingDefault) + antStyle, IncOptions.includeSynthToNameHashingDefault, IncOptions.logRecompileOnMacroDefault) } assert(!(antStyle && nameHashing), "Name hashing and Ant-style cannot be enabled at the same time.") def withTransitiveStep(transitiveStep: Int): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withRecompileAllFraction(recompileAllFraction: Double): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withRelationsDebug(relationsDebug: Boolean): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withApiDebug(apiDebug: Boolean): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withApiDiffContextSize(apiDiffContextSize: Int): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withApiDumpDirectory(apiDumpDirectory: Option[File]): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withNewClassfileManager(newClassfileManager: () => ClassfileManager): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withRecompileOnMacroDef(recompileOnMacroDef: Boolean): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withNameHashing(nameHashing: Boolean): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withIncludeSynthToNameHashing(includeSynthToNameHashing: Boolean): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } def withAntStyle(antStyle: Boolean): IncOptions = { new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, - apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing) + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) + } + + def withLogRecompileOnMacro(logRecompileOnMacro: Boolean): IncOptions = { + new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, + apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, + includeSynthToNameHashing, logRecompileOnMacro) } //- EXPANDED CASE CLASS METHOD BEGIN -// @@ -238,6 +258,7 @@ object IncOptions extends Serializable { private val antStyleDefault: Boolean = false // This should default to false private[sbt] val includeSynthToNameHashingDefault = java.lang.Boolean.getBoolean("sbt.inc.include_synth") + private[sbt] val logRecompileOnMacroDefault = true val Default = IncOptions( // 1. recompile changed sources // 2(3). recompile direct dependencies and transitive public inheritance dependencies of sources with API changes in 1(2). diff --git a/compile/inc/src/main/scala/sbt/inc/IncrementalNameHashing.scala b/compile/inc/src/main/scala/sbt/inc/IncrementalNameHashing.scala index ef7ea1eb9..897bbe582 100644 --- a/compile/inc/src/main/scala/sbt/inc/IncrementalNameHashing.scala +++ b/compile/inc/src/main/scala/sbt/inc/IncrementalNameHashing.scala @@ -13,7 +13,7 @@ import java.io.File */ private final class IncrementalNameHashing(log: Logger, options: IncOptions) extends IncrementalCommon(log, options) { - private val memberRefInvalidator = new MemberRefInvalidator(log) + private val memberRefInvalidator = new MemberRefInvalidator(log, options.logRecompileOnMacro) // Package objects are fragile: if they inherit from an invalidated source, get "class file needed by package is missing" error // This might be too conservative: we probably only need package objects for packages of invalidated sources. diff --git a/compile/inc/src/main/scala/sbt/inc/MemberRefInvalidator.scala b/compile/inc/src/main/scala/sbt/inc/MemberRefInvalidator.scala index 30d5e056b..7202786c2 100644 --- a/compile/inc/src/main/scala/sbt/inc/MemberRefInvalidator.scala +++ b/compile/inc/src/main/scala/sbt/inc/MemberRefInvalidator.scala @@ -50,7 +50,7 @@ import xsbt.api.APIUtil * dependencies unconditionally. On the other hand, if api change is due to modified name hashes * of regular members then we'll invalidate sources that use those names. */ -private[inc] class MemberRefInvalidator(log: Logger) { +private[inc] class MemberRefInvalidator(log: Logger, logRecompileOnMacro: Boolean) { def get[T](memberRef: Relation[File, T], usedNames: Relation[File, String], apiChange: APIChange[_]): T => Set[File] = apiChange match { case _: APIChangeDueToMacroDefinition[_] => new InvalidateDueToMacroDefinition(memberRef) @@ -82,7 +82,7 @@ private[inc] class MemberRefInvalidator(log: Logger) { private class InvalidateDueToMacroDefinition[T](memberRef: Relation[File, T]) extends (T => Set[File]) { def apply(from: T): Set[File] = { val invalidated = memberRef.reverse(from) - if (invalidated.nonEmpty) { + if (invalidated.nonEmpty && logRecompileOnMacro) { log.info(s"Because $from contains a macro definition, the following dependencies are invalidated unconditionally:\n" + formatInvalidated(invalidated)) } diff --git a/notes/0.13.12.markdown b/notes/0.13.12.markdown index 8b8313556..9a8d9162e 100644 --- a/notes/0.13.12.markdown +++ b/notes/0.13.12.markdown @@ -12,7 +12,7 @@ ### Improvements -- When `RecompileOnMacroDef` is enabled, sbt will now print out a info level log indicating that some sources are being recompiled because it's used from a source that contains a macro definition. [#2637][2637] by [@eed3si9n][@eed3si9n] +- When `RecompileOnMacroDef` is enabled, sbt will now print out a info level log indicating that some sources are being recompiled because it's used from a source that contains a macro definition. Can be disabled with `incOptions := incOptions.value.withLogRecompileOnMacro(false)` [#2637][2637]/[#2659][2659] by [@eed3si9n][@eed3si9n]/[@dwijnand][@dwijnand] - Adds Windows script support and native file extensions on Unix platforms. [#2603][2603] by [@ekrich][@ekrich] - Improves loading time of large builds. [#2630][2630] by [@eed3si9n][@eed3si9n] - Adds the ability to call `dependsOn` for the current project inside a `.sbt` file. [#2653][2653] by [@anatolydwnld][@anatolydwnld] @@ -56,6 +56,7 @@ [2002]: https://github.com/sbt/sbt/issues/2002 [1500]: https://github.com/sbt/sbt/issues/1500 [2537]: https://github.com/sbt/sbt/issues/2537 + [2659]: https://github.com/sbt/sbt/pull/2659 [@eed3si9n]: https://github.com/eed3si9n [@jsuereth]: https://github.com/jsuereth diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/Client.scala b/sbt/src/sbt-test/source-dependencies/macro-log/Client.scala new file mode 100644 index 000000000..6f26fea42 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/Client.scala @@ -0,0 +1,7 @@ +package p + +object Client { + def foo = Foo printTree (Foo printTree "foo") + def bar = Bar printTree (Bar printTree "bar") + def baz = Baz printTree (Baz printTree "baz") +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/build.sbt b/sbt/src/sbt-test/source-dependencies/macro-log/build.sbt new file mode 100644 index 000000000..813827024 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/build.sbt @@ -0,0 +1,19 @@ +dependsOn(macros) + +scalaVersion in Global := "2.11.8" + +val macros = project settings (libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value) + +def expectedStringFor(l: String) = + s"Because $l contains a macro definition, the following dependencies are invalidated unconditionally" + +TaskKey[Unit]("checkPresent1") := check(expectedStringFor("p.Foo$"), expectPresent = true).value +TaskKey[Unit]("checkMissing2") := check(expectedStringFor("p.Bar$"), expectPresent = false).value +TaskKey[Unit]("checkPresent3") := check(expectedStringFor("p.Baz$"), expectPresent = true).value + +def check(expectedString: String, expectPresent: Boolean) = Def task { + val last = IO read (BuiltinCommands lastLogFile state.value).get + val present = last contains expectedString + if (expectPresent && !present) sys error "Expected there to be a log message for macro recompilation" + if (!expectPresent && present) sys error "Expected there to NOT be a log message for macro recompilation" +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/macros/Bar.scala b/sbt/src/sbt-test/source-dependencies/macro-log/macros/Bar.scala new file mode 100644 index 000000000..8c7834786 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/macros/Bar.scala @@ -0,0 +1,13 @@ +package p + +import scala.language.experimental.macros +import scala.reflect.macros._ + +object Bar { + def printTree(arg: Any): Any = macro BarMacros.printTreeImpl +} + +class BarMacros(val c: blackbox.Context) { + import c.universe._ + def printTreeImpl(arg: Tree): Tree = Literal(Constant("Bar1: " + arg)) +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/macros/Baz.scala b/sbt/src/sbt-test/source-dependencies/macro-log/macros/Baz.scala new file mode 100644 index 000000000..fcc0b52f8 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/macros/Baz.scala @@ -0,0 +1,13 @@ +package p + +import scala.language.experimental.macros +import scala.reflect.macros._ + +object Baz { + def printTree(arg: Any): Any = macro BazMacros.printTreeImpl +} + +class BazMacros(val c: blackbox.Context) { + import c.universe._ + def printTreeImpl(arg: Tree): Tree = Literal(Constant("Baz1: " + arg)) +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/macros/Foo.scala b/sbt/src/sbt-test/source-dependencies/macro-log/macros/Foo.scala new file mode 100644 index 000000000..5e7f741d6 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/macros/Foo.scala @@ -0,0 +1,13 @@ +package p + +import scala.language.experimental.macros +import scala.reflect.macros._ + +object Foo { + def printTree(arg: Any): Any = macro FooMacros.printTreeImpl +} + +class FooMacros(val c: blackbox.Context) { + import c.universe._ + def printTreeImpl(arg: Tree): Tree = Literal(Constant("Foo1: " + arg)) +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Bar.scala b/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Bar.scala new file mode 100644 index 000000000..208d3c8c7 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Bar.scala @@ -0,0 +1,13 @@ +package p + +import scala.language.experimental.macros +import scala.reflect.macros._ + +object Bar { + def printTree(arg: Any): Any = macro BarMacros.printTreeImpl +} + +class BarMacros(val c: blackbox.Context) { + import c.universe._ + def printTreeImpl(arg: Tree): Tree = Literal(Constant("Bar2: " + arg)) +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Baz.scala b/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Baz.scala new file mode 100644 index 000000000..7b8b1f620 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Baz.scala @@ -0,0 +1,13 @@ +package p + +import scala.language.experimental.macros +import scala.reflect.macros._ + +object Baz { + def printTree(arg: Any): Any = macro BazMacros.printTreeImpl +} + +class BazMacros(val c: blackbox.Context) { + import c.universe._ + def printTreeImpl(arg: Tree): Tree = Literal(Constant("Baz2: " + arg)) +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Foo.scala b/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Foo.scala new file mode 100644 index 000000000..bfd3a6cef --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/macros/changes/Foo.scala @@ -0,0 +1,13 @@ +package p + +import scala.language.experimental.macros +import scala.reflect.macros._ + +object Foo { + def printTree(arg: Any): Any = macro FooMacros.printTreeImpl +} + +class FooMacros(val c: blackbox.Context) { + import c.universe._ + def printTreeImpl(arg: Tree): Tree = Literal(Constant("Foo2: " + arg)) +} diff --git a/sbt/src/sbt-test/source-dependencies/macro-log/test b/sbt/src/sbt-test/source-dependencies/macro-log/test new file mode 100644 index 000000000..31c5af41c --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/macro-log/test @@ -0,0 +1,18 @@ +> compile +$ copy-file macros/changes/Foo.scala macros/Foo.scala +> compile +> checkPresent1 + +> set incOptions := incOptions.value.withLogRecompileOnMacro(false) + +> compile +$ copy-file macros/changes/Bar.scala macros/Bar.scala +> compile +> checkMissing2 + +> set incOptions := incOptions.value.withLogRecompileOnMacro(true) + +> compile +$ copy-file macros/changes/Baz.scala macros/Baz.scala +> compile +> checkPresent3