summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-10-22 22:06:27 -0700
committerLi Haoyi <haoyi.sg@gmail.com>2017-10-22 22:06:27 -0700
commit822be02a29d7073c7f2fe9b74df7cc42e56d762c (patch)
tree1812e53e1dc8626e13f70300aa34121c23b9e92d
parentd57ad0b63b54076d9182fdb75df9e38c8b30b58c (diff)
downloadmill-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
-rw-r--r--src/main/scala/forge/DefCtx.scala45
-rw-r--r--src/main/scala/forge/Evaluator.scala8
-rw-r--r--src/main/scala/forge/Target.scala2
-rw-r--r--src/test/scala/forge/ForgeTests.scala117
-rw-r--r--src/test/scala/forge/StaticContextTests.scala36
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)
-
- }
-}