Merge pull request #2659 from dwijnand/log-recompile-on-macro-opt

Fixes #2654 Silence macro recompilation info message
This commit is contained in:
eugene yokota 2016-07-07 22:37:17 -04:00 committed by GitHub
commit 9ea9abf98d
13 changed files with 162 additions and 18 deletions

View File

@ -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).

View File

@ -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.

View File

@ -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))
}

View File

@ -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

View File

@ -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")
}

View File

@ -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"
}

View File

@ -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))
}

View File

@ -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))
}

View File

@ -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))
}

View File

@ -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))
}

View File

@ -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))
}

View File

@ -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))
}

View File

@ -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