aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-07-02 15:55:34 +0200
committerJason Zaugg <jzaugg@gmail.com>2013-07-03 10:04:55 +0200
commit82232ec47effb4a6b67b3a0792e1c7600e2d31b7 (patch)
treeed9925418aa0a631d1d25fd1be30f5d508e81b24 /src/test
parentd63b63f536aafa494c70835526174be1987050de (diff)
downloadscala-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')
-rw-r--r--src/test/scala/scala/async/TreeInterrogation.scala6
-rw-r--r--src/test/scala/scala/async/neg/LocalClasses0Spec.scala123
-rw-r--r--src/test/scala/scala/async/run/anf/AnfTransformSpec.scala2
-rw-r--r--src/test/scala/scala/async/run/nesteddef/NestedDef.scala56
-rw-r--r--src/test/scala/scala/async/run/toughtype/ToughType.scala38
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))
+ }
+ }
}