diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-07-02 15:55:34 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-07-03 10:04:55 +0200 |
commit | 82232ec47effb4a6b67b3a0792e1c7600e2d31b7 (patch) | |
tree | ed9925418aa0a631d1d25fd1be30f5d508e81b24 /src/test/scala | |
parent | d63b63f536aafa494c70835526174be1987050de (diff) | |
download | scala-async-82232ec47effb4a6b67b3a0792e1c7600e2d31b7.tar.gz scala-async-82232ec47effb4a6b67b3a0792e1c7600e2d31b7.tar.bz2 scala-async-82232ec47effb4a6b67b3a0792e1c7600e2d31b7.zip |
An overdue overhaul of macro internals.
- Avoid reset + retypecheck, instead hang onto the original types/symbols
- Eliminated duplication between AsyncDefinitionUseAnalyzer and ExprBuilder
- Instead, decide what do lift *after* running ExprBuilder
- Account for transitive references local classes/objects and lift them
as needed.
- Make the execution context an regular implicit parameter of the macro
- Fixes interaction with existential skolems and singleton types
Fixes #6, #13, #16, #17, #19, #21.
Diffstat (limited to 'src/test/scala')
5 files changed, 115 insertions, 110 deletions
diff --git a/src/test/scala/scala/async/TreeInterrogation.scala b/src/test/scala/scala/async/TreeInterrogation.scala index 43393a7..a06437d 100644 --- a/src/test/scala/scala/async/TreeInterrogation.scala +++ b/src/test/scala/scala/async/TreeInterrogation.scala @@ -40,8 +40,8 @@ class TreeInterrogation { val varDefs = tree1.collect { case ValDef(mods, name, _, _) if mods.hasFlag(Flag.MUTABLE) => name } - varDefs.map(_.decoded.trim).toSet mustBe (Set("state$async", "await$1", "await$2")) - varDefs.map(_.decoded.trim).toSet mustBe (Set("state$async", "await$1", "await$2")) + varDefs.map(_.decoded.trim).toSet mustBe (Set("state", "await$1", "await$2")) + varDefs.map(_.decoded.trim).toSet mustBe (Set("state", "await$1", "await$2")) val defDefs = tree1.collect { case t: Template => @@ -68,7 +68,7 @@ object TreeInterrogation extends App { withDebug { val cm = reflect.runtime.currentMirror - val tb = mkToolbox("-cp ${toolboxClasspath} -Xprint:flatten") + val tb = mkToolbox("-cp ${toolboxClasspath} -Xprint:typer -uniqid") import scala.async.Async._ val tree = tb.parse( """ import _root_.scala.async.AsyncId.{async, await} diff --git a/src/test/scala/scala/async/neg/LocalClasses0Spec.scala b/src/test/scala/scala/async/neg/LocalClasses0Spec.scala index 2569303..dcd9bb8 100644 --- a/src/test/scala/scala/async/neg/LocalClasses0Spec.scala +++ b/src/test/scala/scala/async/neg/LocalClasses0Spec.scala @@ -5,121 +5,32 @@ package scala.async package neg -/** - * Copyright (C) 2012 Typesafe Inc. <http://www.typesafe.com> - */ - import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.junit.Test @RunWith(classOf[JUnit4]) class LocalClasses0Spec { - @Test - def `reject a local class`() { - expectError("Local case class Person illegal within `async` block") { - """ - | import scala.concurrent.ExecutionContext.Implicits.global - | import scala.async.Async._ - | - | async { - | case class Person(name: String) - | } - """.stripMargin - } + def localClassCrashIssue16() { + import scala.async.AsyncId.{async, await} + async { + class B { def f = 1 } + await(new B()).f + } mustBe 1 } @Test - def `reject a local class 2`() { - expectError("Local case class Person illegal within `async` block") { - """ - | import scala.concurrent.{Future, ExecutionContext} - | import ExecutionContext.Implicits.global - | import scala.async.Async._ - | - | async { - | case class Person(name: String) - | val fut = Future { 5 } - | val x = await(fut) - | x - | } - """.stripMargin - } + def nestedCaseClassAndModuleAllowed() { + import AsyncId.{await, async} + async { + trait Base { def base = 0} + await(0) + case class Person(name: String) extends Base + val fut = async { "bob" } + val x = Person(await(fut)) + x.base + x.name + } mustBe "bob" } - - @Test - def `reject a local class 3`() { - expectError("Local case class Person illegal within `async` block") { - """ - | import scala.concurrent.{Future, ExecutionContext} - | import ExecutionContext.Implicits.global - | import scala.async.Async._ - | - | async { - | val fut = Future { 5 } - | val x = await(fut) - | case class Person(name: String) - | x - | } - """.stripMargin - } - } - - @Test - def `reject a local class with symbols in its name`() { - expectError("Local case class :: illegal within `async` block") { - """ - | import scala.concurrent.{Future, ExecutionContext} - | import ExecutionContext.Implicits.global - | import scala.async.Async._ - | - | async { - | val fut = Future { 5 } - | val x = await(fut) - | case class ::(name: String) - | x - | } - """.stripMargin - } - } - - @Test - def `reject a nested local class`() { - expectError("Local case class Person illegal within `async` block") { - """ - | import scala.concurrent.{Future, ExecutionContext} - | import ExecutionContext.Implicits.global - | import scala.async.Async._ - | - | async { - | val fut = Future { 5 } - | val x = 2 + 2 - | var y = 0 - | if (x > 0) { - | case class Person(name: String) - | y = await(fut) - | } else { - | y = x - | } - | y - | } - """.stripMargin - } - } - - @Test - def `reject a local singleton object`() { - expectError("Local object Person illegal within `async` block") { - """ - | import scala.concurrent.ExecutionContext.Implicits.global - | import scala.async.Async._ - | - | async { - | object Person { val name = "Joe" } - | } - """.stripMargin - } - } - } diff --git a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala index 7be6299..abce3ce 100644 --- a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala +++ b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala @@ -238,7 +238,7 @@ class AnfTransformSpec { val res = async { var i = 0 def get = {i += 1; i} - foo(get)(get) + foo(get)(await(get)) } res mustBe "a0 = 1, b0 = 2" } diff --git a/src/test/scala/scala/async/run/nesteddef/NestedDef.scala b/src/test/scala/scala/async/run/nesteddef/NestedDef.scala index ee0a78e..cf74602 100644 --- a/src/test/scala/scala/async/run/nesteddef/NestedDef.scala +++ b/src/test/scala/scala/async/run/nesteddef/NestedDef.scala @@ -37,4 +37,60 @@ class NestedDef { } result mustBe ((0d, 44d, 2)) } + + // We must lift `foo` and `bar` in the next two tests. + @Test + def nestedDefTransitive1() { + import AsyncId._ + val result = async { + val a = 0 + val x = await(a) - 1 + def bar = a + def foo = bar + foo + } + result mustBe 0 + } + + @Test + def nestedDefTransitive2() { + import AsyncId._ + val result = async { + val a = 0 + val x = await(a) - 1 + def bar = a + def foo = bar + 0 + } + result mustBe 0 + } + + + // checking that our use/definition analysis doesn't cycle. + @Test + def mutuallyRecursive1() { + import AsyncId._ + val result = async { + val a = 0 + val x = await(a) - 1 + def foo: Int = if (true) 0 else bar + def bar: Int = if (true) 0 else foo + bar + } + result mustBe 0 + } + + // checking that our use/definition analysis doesn't cycle. + @Test + def mutuallyRecursive2() { + import AsyncId._ + val result = async { + val a = 0 + def foo: Int = if (true) 0 else bar + def bar: Int = if (true) 0 else foo + val x = await(a) - 1 + bar + } + result mustBe 0 + } } diff --git a/src/test/scala/scala/async/run/toughtype/ToughType.scala b/src/test/scala/scala/async/run/toughtype/ToughType.scala index 83f5a2d..6fcd966 100644 --- a/src/test/scala/scala/async/run/toughtype/ToughType.scala +++ b/src/test/scala/scala/async/run/toughtype/ToughType.scala @@ -67,4 +67,42 @@ class ToughTypeSpec { await(f(2)) } mustBe 3 } + + @Test def existentialBindIssue19() { + import AsyncId.{await, async} + def m7(a: Any) = async { + a match { + case s: Seq[_] => + val x = s.size + var ss = s + ss = s + await(x) + } + } + m7(Nil) mustBe 0 + } + + @Test def existentialBind2Issue19() { + import scala.async.Async._, scala.concurrent.ExecutionContext.Implicits.global + def conjure[T]: T = null.asInstanceOf[T] + + def m3 = async { + val p: List[Option[_]] = conjure[List[Option[_]]] + await(future(1)) + } + + def m4 = async { + await(future[List[_]](Nil)) + } + } + + @Test def singletonTypeIssue17() { + import scala.async.AsyncId.{async, await} + class A { class B } + async { + val a = new A + def foo(b: a.B) = 0 + await(foo(new a.B)) + } + } } |