diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-10-22 22:06:27 -0700 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-10-22 22:06:27 -0700 |
commit | 822be02a29d7073c7f2fe9b74df7cc42e56d762c (patch) | |
tree | 1812e53e1dc8626e13f70300aa34121c23b9e92d /src | |
parent | d57ad0b63b54076d9182fdb75df9e38c8b30b58c (diff) | |
download | mill-822be02a29d7073c7f2fe9b74df7cc42e56d762c.tar.gz mill-822be02a29d7073c7f2fe9b74df7cc42e56d762c.tar.bz2 mill-822be02a29d7073c7f2fe9b74df7cc42e56d762c.zip |
Swap over to new macro-based `DefCtx` injection, rather than relying on `StaticContext`
This should let us avoid the same `StaticContext` being re-used by multiple implicit use-sites within a block, causing confusion.
`ForgeTests.evaluate.anonTriple` still doesn't pass for unrelated reasons
Diffstat (limited to 'src')
-rw-r--r-- | src/main/scala/forge/DefCtx.scala | 45 | ||||
-rw-r--r-- | src/main/scala/forge/Evaluator.scala | 8 | ||||
-rw-r--r-- | src/main/scala/forge/Target.scala | 2 | ||||
-rw-r--r-- | src/test/scala/forge/ForgeTests.scala | 117 | ||||
-rw-r--r-- | src/test/scala/forge/StaticContextTests.scala | 36 |
5 files changed, 86 insertions, 122 deletions
diff --git a/src/main/scala/forge/DefCtx.scala b/src/main/scala/forge/DefCtx.scala index 251e671b..b9c02602 100644 --- a/src/main/scala/forge/DefCtx.scala +++ b/src/main/scala/forge/DefCtx.scala @@ -5,31 +5,30 @@ import scala.language.experimental.macros import scala.reflect.macros._ -case class DefCtx(staticEnclosing: Option[String]) +sealed abstract class DefCtx(val value: Option[String]) object DefCtx{ - case class StaticContext(value: Boolean) - object StaticContext { - implicit def default: StaticContext = macro applyImpl - def rec(c: Context)(expr: c.Symbol): Boolean = { - import c.universe._ - // Classes and traits and such - if(!expr.isModuleClass && expr.isClass) false - // Method contents - else if(expr.isMethod) false - else if(expr.owner == NoSymbol) true - else rec(c)(expr.owner) - } + implicit object Anonymous extends DefCtx(None) + case class Labeled(label: String) extends DefCtx(Some(label)) +} - def applyImpl(c: Context): c.Expr[StaticContext] = { - import c.universe._ - val staticContext = rec(c)(c.internal.enclosingOwner) - c.Expr[StaticContext](q"forge.DefCtx.StaticContext($staticContext)") - } - } +object T{ + def apply[T](expr: T): T = macro applyImpl[T] - implicit def default(implicit enc: sourcecode.Enclosing, - sc: StaticContext) = { - if (sc.value) DefCtx(Some(enc.value)) - else DefCtx(None) + def applyImpl[T: c.WeakTypeTag](c: Context)(expr: c.Expr[T]): c.Expr[T] = { + import c.universe._ + val transformed = expr.tree match{ + case Apply(fun, args) => + var transformed = false + val newArgs = args.map{ + case x if x.tpe == weakTypeOf[DefCtx.Anonymous.type] => + transformed = true + q"forge.DefCtx.Labeled(sourcecode.Enclosing())" + case x => x + } + assert(transformed) + Apply(fun, newArgs) + case _ => ??? + } + c.Expr[T](transformed) } }
\ No newline at end of file diff --git a/src/main/scala/forge/Evaluator.scala b/src/main/scala/forge/Evaluator.scala index f341c9cb..d6ff39a2 100644 --- a/src/main/scala/forge/Evaluator.scala +++ b/src/main/scala/forge/Evaluator.scala @@ -20,10 +20,10 @@ class Evaluator(workspacePath: jnio.Path, for (target <- sortedTargets){ val inputResults = target.inputs.map(results).toIndexedSeq - val targetDestPath = target.defCtx.staticEnclosing match{ + val targetDestPath = target.defCtx.value match{ case Some(enclosingStr) => val targetDestPath = workspacePath.resolve( - jnio.Paths.get(enclosingStr.stripSuffix(enclosingBase.staticEnclosing.getOrElse(""))) + jnio.Paths.get(enclosingStr.stripSuffix(enclosingBase.value.getOrElse(""))) ) deleteRec(targetDestPath) targetDestPath @@ -32,13 +32,13 @@ class Evaluator(workspacePath: jnio.Path, } val inputsHash = inputResults.hashCode - target.defCtx.staticEnclosing.flatMap(resultCache.get) match{ + target.defCtx.value.flatMap(resultCache.get) match{ case Some((hash, res)) if hash == inputsHash && !target.dirty => results(target) = res case _ => evaluated.append(target) val res = target.evaluate(new Args(inputResults, targetDestPath)) - for(label <- target.defCtx.staticEnclosing) { + for(label <- target.defCtx.value) { resultCache(label) = (inputsHash, res) } results(target) = res diff --git a/src/main/scala/forge/Target.scala b/src/main/scala/forge/Target.scala index acbb8449..d7edc188 100644 --- a/src/main/scala/forge/Target.scala +++ b/src/main/scala/forge/Target.scala @@ -14,7 +14,7 @@ trait TargetOps[T]{ this: Target[T] => this.zip(other).map(s.apply _ tupled) } - override def toString = defCtx.staticEnclosing match{ + override def toString = defCtx.value match{ case None => this.getClass.getSimpleName + "@" + Integer.toHexString(System.identityHashCode(this)) case Some(s) => this.getClass.getName + "@" + s } diff --git a/src/test/scala/forge/ForgeTests.scala b/src/test/scala/forge/ForgeTests.scala index 07e753c6..ae6cfcf4 100644 --- a/src/test/scala/forge/ForgeTests.scala +++ b/src/test/scala/forge/ForgeTests.scala @@ -6,28 +6,28 @@ import java.nio.{file => jnio} object ForgeTests extends TestSuite{ val tests = Tests{ - implicit def fakeStaticContext = DefCtx.StaticContext(true) val evaluator = new Evaluator(jnio.Paths.get("target/workspace"), implicitly) object Singleton { - val single = test() + val single = T{ test() } } object Pair { - val up = test() - val down = test(up) + val up = T{ test() } + val down = T{ test(up) } } + object AnonTriple{ - val up = test() - val down = test(test(up)) + val up = T{ test() } + val down = T{ test(test(up)) } } object Diamond{ - val up = test() - val left = test(up) - val right = test(up) - val down = test(left, right) + val up = T{ test() } + val left = T{ test(up) } + val right = T{ test(up) } + val down = T{ test(left, right) } } object AnonDiamond{ - val up = test() - val down = test(test(up), test(up)) + val up = T{ test() } + val down = T{ test(test(up), test(up)) } } 'topoSortedTransitiveTargets - { @@ -35,6 +35,7 @@ object ForgeTests extends TestSuite{ val result = Evaluator.topoSortedTransitiveTargets(targets) assert(result == expected) } + 'singleton - check( targets = Seq(Singleton.single), expected = Seq(Singleton.single) @@ -60,60 +61,60 @@ object ForgeTests extends TestSuite{ Diamond.down ) ) + } + 'evaluate - { + def check(targets: Seq[Target[_]], + values: Seq[Any], + evaluated: Seq[Target[_]]) = { + val Evaluator.Results(returnedValues, returnedEvaluated) = evaluator.evaluate(targets) + assert( + returnedValues == values, + returnedEvaluated == evaluated + ) - 'evaluate - { - def check(targets: Seq[Target[_]], - values: Seq[Any], - evaluated: Seq[Target[_]]) = { - val Evaluator.Results(returnedValues, returnedEvaluated) = evaluator.evaluate(targets) - assert( - returnedValues == values, - returnedEvaluated == evaluated - ) - - } - 'singleton - { - import Singleton._ - // First time the target is evaluated - check(Seq(single), values = Seq(0), evaluated = Seq(single)) - // Second time the value is already cached, so no evaluation needed - check(Seq(single), values = Seq(0), evaluated = Seq()) - single.counter += 1 - // After incrementing the counter, it forces re-evaluation - check(Seq(single), values = Seq(1), evaluated = Seq(single)) - // Then it's cached again - check(Seq(single), values = Seq(1), evaluated = Seq()) - } - 'pair - { - import Pair._ - check(Seq(down), values = Seq(0), evaluated = Seq(up, down)) - check(Seq(down), values = Seq(0), evaluated = Seq()) + } + 'singleton - { + import Singleton._ + // First time the target is evaluated + check(Seq(single), values = Seq(0), evaluated = Seq(single)) + // Second time the value is already cached, so no evaluation needed + check(Seq(single), values = Seq(0), evaluated = Seq()) + single.counter += 1 + // After incrementing the counter, it forces re-evaluation + check(Seq(single), values = Seq(1), evaluated = Seq(single)) + // Then it's cached again + check(Seq(single), values = Seq(1), evaluated = Seq()) + } + 'pair - { + import Pair._ + check(Seq(down), values = Seq(0), evaluated = Seq(up, down)) + check(Seq(down), values = Seq(0), evaluated = Seq()) - down.counter += 1 - check(Seq(down), values = Seq(1), evaluated = Seq(down)) - check(Seq(down), values = Seq(1), evaluated = Seq()) + down.counter += 1 + check(Seq(down), values = Seq(1), evaluated = Seq(down)) + check(Seq(down), values = Seq(1), evaluated = Seq()) - up.counter += 1 - check(Seq(down), values = Seq(2), evaluated = Seq(up, down)) - check(Seq(down), values = Seq(2), evaluated = Seq()) - } - 'anonTriple - { - import AnonTriple._ - val middle = down.inputs(0) - check(Seq(down), values = Seq(0), evaluated = Seq(up, middle, down)) - check(Seq(down), values = Seq(0), evaluated = Seq()) + up.counter += 1 + check(Seq(down), values = Seq(2), evaluated = Seq(up, down)) + check(Seq(down), values = Seq(2), evaluated = Seq()) + } + 'anonTriple - { + import AnonTriple._ + val middle = down.inputs(0) + check(Seq(down), values = Seq(0), evaluated = Seq(up, middle, down)) + check(Seq(down), values = Seq(0), evaluated = Seq()) - down.counter += 1 - check(Seq(down), values = Seq(1), evaluated = Seq(middle, down)) - check(Seq(down), values = Seq(1), evaluated = Seq()) + down.counter += 1 + check(Seq(down), values = Seq(1), evaluated = Seq(middle, down)) + check(Seq(down), values = Seq(1), evaluated = Seq()) - up.counter += 1 - check(Seq(down), values = Seq(2), evaluated = Seq(up, middle, down)) - check(Seq(down), values = Seq(2), evaluated = Seq()) - } + up.counter += 1 + check(Seq(down), values = Seq(2), evaluated = Seq(up, middle, down)) + check(Seq(down), values = Seq(2), evaluated = Seq()) } } + // 'full - { // val sourceRoot = Target.path(jnio.Paths.get("src/test/resources/example/src")) // val resourceRoot = Target.path(jnio.Paths.get("src/test/resources/example/resources")) diff --git a/src/test/scala/forge/StaticContextTests.scala b/src/test/scala/forge/StaticContextTests.scala deleted file mode 100644 index 0e764fef..00000000 --- a/src/test/scala/forge/StaticContextTests.scala +++ /dev/null @@ -1,36 +0,0 @@ -package forge -import DefCtx.StaticContext -import utest._ -class Helper{ - val static = implicitly[StaticContext] - object Nested { - val static = implicitly[StaticContext] - } - def method = implicitly[StaticContext] -} -object StaticContextTests extends TestSuite{ - val static = implicitly[StaticContext] - object Nested{ - val static = implicitly[StaticContext] - def method = implicitly[StaticContext] - class Helper{ - val static = implicitly[StaticContext] - } - } - - def method = implicitly[StaticContext] - val tests = Tests{ - val helper = new Helper() - 'inObject - assert(static.value) - 'inClass- assert(!helper.static.value) - 'inMethod - assert(!method.value) - - 'inObjectObject - assert(Nested.static.value) - 'inObjectClass- assert(!helper.static.value) - 'inObjectMethod- assert(!Nested.method.value) - - 'inClassObject - assert(!helper.Nested.static.value) - 'inClassMethod- assert(!helper.method.value) - - } -} |