From 90f13e71d48c40e876e350501c4ab5894d6a1f5b Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 10 Apr 2013 15:23:02 +0200 Subject: Address deprecation warnings in Scala 2.10.1 --- build.sbt | 4 ++-- src/main/scala/scala/async/Async.scala | 2 +- src/main/scala/scala/async/AsyncAnalysis.scala | 2 +- src/main/scala/scala/async/ExprBuilder.scala | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index f1ded58..c0e062e 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ -scalaVersion := "2.10.0" +scalaVersion := "2.10.1" -organization := "org.typesafe.async" +organization := "org.typesafe.async" // TODO new org name under scala-lang. name := "scala-async" diff --git a/src/main/scala/scala/async/Async.scala b/src/main/scala/scala/async/Async.scala index 12fe428..8323ac5 100644 --- a/src/main/scala/scala/async/Async.scala +++ b/src/main/scala/scala/async/Async.scala @@ -152,7 +152,7 @@ abstract class AsyncBase { else { Block(List[Tree]( stateMachine, - ValDef(NoMods, name.stateMachine, stateMachineType, New(Ident(name.stateMachineT), Nil)), + ValDef(NoMods, name.stateMachine, stateMachineType, Apply(Select(New(Ident(name.stateMachineT)), nme.CONSTRUCTOR), Nil)), futureSystemOps.spawn(Apply(selectStateMachine(name.apply), Nil)) ), futureSystemOps.promiseToFuture(c.Expr[futureSystem.Prom[T]](selectStateMachine(name.result))).tree) diff --git a/src/main/scala/scala/async/AsyncAnalysis.scala b/src/main/scala/scala/async/AsyncAnalysis.scala index 9184960..4f55f1b 100644 --- a/src/main/scala/scala/async/AsyncAnalysis.scala +++ b/src/main/scala/scala/async/AsyncAnalysis.scala @@ -159,7 +159,7 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C, asyncBase: Asy nextChunk() case vd: ValDef => super.traverse(tree) - valDefChunkId += (vd.symbol ->(vd, chunkId)) + valDefChunkId += (vd.symbol -> (vd -> chunkId)) val isPatternBinder = vd.name.toString.contains(name.bindSuffix) if (isAwait(vd.rhs) || isPatternBinder) valDefsToLift += vd case as: Assign => diff --git a/src/main/scala/scala/async/ExprBuilder.scala b/src/main/scala/scala/async/ExprBuilder.scala index 180e7b9..adb6b3d 100644 --- a/src/main/scala/scala/async/ExprBuilder.scala +++ b/src/main/scala/scala/async/ExprBuilder.scala @@ -33,7 +33,7 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c: final def body: c.Tree = stats match { case stat :: Nil => stat - case _ => Block(stats: _*) + case init :+ last => Block(init, last) } } @@ -94,8 +94,8 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c: c.Expr[scala.util.Try[T]]( TypeApply(Select(Ident(name.tr), newTermName("asInstanceOf")), List(TypeTree(weakTypeOf[scala.util.Try[T]]))))).tree, - Block(List(tryGetTree, mkStateTree(nextState), mkResumeApply): _*) - ) + Block(List(tryGetTree, mkStateTree(nextState), mkResumeApply), c.literalUnit.tree) + ) Some(mkHandlerCase(state, List(ifIsFailureTree))) } @@ -146,7 +146,7 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c: // 1. build changed if-else tree // 2. insert that tree at the end of the current state val cond = renameReset(condTree) - def mkBranch(state: Int) = Block(mkStateTree(state), mkResumeApply) + def mkBranch(state: Int) = Block(mkStateTree(state) :: Nil, mkResumeApply) this += If(cond, mkBranch(thenState), mkBranch(elseState)) new AsyncStateWithoutAwait(stats.toList, state) } @@ -177,7 +177,7 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c: } def resultWithLabel(startLabelState: Int): AsyncState = { - this += Block(mkStateTree(startLabelState), mkResumeApply) + this += Block(mkStateTree(startLabelState) :: Nil, mkResumeApply) new AsyncStateWithoutAwait(stats.toList, state) } @@ -387,7 +387,7 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c: Assign(Ident(name.state), c.literal(nextState).tree) private def mkHandlerCase(num: Int, rhs: List[c.Tree]): CaseDef = - mkHandlerCase(num, Block(rhs: _*)) + mkHandlerCase(num, Block(rhs, c.literalUnit.tree)) private def mkHandlerCase(num: Int, rhs: c.Tree): CaseDef = CaseDef(c.literal(num).tree, EmptyTree, rhs) -- cgit v1.2.3 From dffb7c9d591d6b90607f49a95f95058031d37433 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 10 Apr 2013 15:29:55 +0200 Subject: Address lint warnings. --- src/test/scala/scala/async/run/nesteddef/NestedDef.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/scala/scala/async/run/nesteddef/NestedDef.scala b/src/test/scala/scala/async/run/nesteddef/NestedDef.scala index 2baef0d..ee0a78e 100644 --- a/src/test/scala/scala/async/run/nesteddef/NestedDef.scala +++ b/src/test/scala/scala/async/run/nesteddef/NestedDef.scala @@ -20,7 +20,7 @@ class NestedDef { def foo(z: Any) = (a.toDouble, bar(x).toDouble, z) foo(await(2)) } - result mustBe (0d, 44d, 2) + result mustBe ((0d, 44d, 2)) } @@ -35,6 +35,6 @@ class NestedDef { val foo = (z: Any) => (a.toDouble, bar(x).toDouble, z) foo(await(2)) } - result mustBe (0d, 44d, 2) + result mustBe ((0d, 44d, 2)) } } -- cgit v1.2.3 From 78499a5d509fef4bcdf517f75a8bb29f3a54f569 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 10 Apr 2013 15:38:07 +0200 Subject: Temporarily comment out tests that are failing under 2.10.1. --- src/test/scala/scala/async/TreeInterrogation.scala | 17 ++++----- .../scala/async/run/anf/AnfTransformSpec.scala | 35 ++++++++++--------- src/test/scala/scala/async/run/match0/Match0.scala | 35 ++++++++++--------- .../scala/async/run/toughtype/ToughType.scala | 40 ++++++++++++---------- 4 files changed, 66 insertions(+), 61 deletions(-) diff --git a/src/test/scala/scala/async/TreeInterrogation.scala b/src/test/scala/scala/async/TreeInterrogation.scala index 93cfdf5..2bc4770 100644 --- a/src/test/scala/scala/async/TreeInterrogation.scala +++ b/src/test/scala/scala/async/TreeInterrogation.scala @@ -70,15 +70,16 @@ object TreeInterrogation extends App { val cm = reflect.runtime.currentMirror val tb = mkToolbox("-cp target/scala-2.10/classes -Xprint:flatten") val tree = tb.parse( - """ import scala.async.AsyncId.{async, await} - | async { - | await(1) - | val neg1 = -1 - | val a = await(1) - | val f = { case x => ({case x => neg1 * x}: PartialFunction[Int, Int])(x + a) }: PartialFunction[Int, Int] - | await(f(2)) + """ async { + | val x = 1 + | val opt = Some("") + | await(0) + | val o @ Some(y) = opt + | + | { + | val o @ Some(y) = Some(".") + | } | } - | () | """.stripMargin) println(tree) val tree1 = tb.typeCheck(tree.duplicate) diff --git a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala index 41c13e0..03db205 100644 --- a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala +++ b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala @@ -112,23 +112,24 @@ class AnfTransformSpec { State.result mustBe (14) } - @Test - def `inlining block does not produce duplicate definition`() { - import scala.async.AsyncId - - AsyncId.async { - val f = 12 - val x = AsyncId.await(f) - - { - type X = Int - val x: X = 42 - println(x) - } - type X = Int - x: X - } - } +// TODO 2.10.1 +// @Test +// def `inlining block does not produce duplicate definition`() { +// import scala.async.AsyncId +// +// AsyncId.async { +// val f = 12 +// val x = AsyncId.await(f) +// +// { +// type X = Int +// val x: X = 42 +// println(x) +// } +// type X = Int +// x: X +// } +// } @Test def `inlining block in tail position does not produce duplicate definition`() { diff --git a/src/test/scala/scala/async/run/match0/Match0.scala b/src/test/scala/scala/async/run/match0/Match0.scala index 7624838..79a4e35 100644 --- a/src/test/scala/scala/async/run/match0/Match0.scala +++ b/src/test/scala/scala/async/run/match0/Match0.scala @@ -83,23 +83,24 @@ class MatchSpec { result mustBe (2) } - @Test def `support await referring to pattern matching vals`() { - import AsyncId.{async, await} - val result = async { - val x = 1 - val opt = Some("") - await(0) - val o @ Some(y) = opt - - { - val o @ Some(y) = Some(".") - } - - await(0) - await((o, y.isEmpty)) - } - result mustBe ((Some(""), true)) - } +// TODO 2.10.1 +// @Test def `support await referring to pattern matching vals`() { +// import AsyncId.{async, await} +// val result = async { +// val x = 1 +// val opt = Some("") +// await(0) +// val o @ Some(y) = opt +// +// { +// val o @ Some(y) = Some(".") +// } +// +// await(0) +// await((o, y.isEmpty)) +// } +// result mustBe ((Some(""), true)) +// } @Test def `await in scrutinee`() { import AsyncId.{async, await} diff --git a/src/test/scala/scala/async/run/toughtype/ToughType.scala b/src/test/scala/scala/async/run/toughtype/ToughType.scala index 83f5a2d..ab0b60d 100644 --- a/src/test/scala/scala/async/run/toughtype/ToughType.scala +++ b/src/test/scala/scala/async/run/toughtype/ToughType.scala @@ -37,26 +37,28 @@ class ToughTypeSpec { res._1 mustBe (Nil) } - @Test def patternMatchingPartialFunction() { - import AsyncId.{await, async} - async { - await(1) - val a = await(1) - val f = { case x => x + a }: PartialFunction[Int, Int] - await(f(2)) - } mustBe 3 - } +// TODO 2.10.1 +// @Test def patternMatchingPartialFunction() { +// import AsyncId.{await, async} +// async { +// await(1) +// val a = await(1) +// val f = { case x => x + a }: PartialFunction[Int, Int] +// await(f(2)) +// } mustBe 3 +// } - @Test def patternMatchingPartialFunctionNested() { - import AsyncId.{await, async} - async { - await(1) - val neg1 = -1 - val a = await(1) - val f = { case x => ({case x => neg1 * x}: PartialFunction[Int, Int])(x + a) }: PartialFunction[Int, Int] - await(f(2)) - } mustBe -3 - } +// TODO 2.10.1 +// @Test def patternMatchingPartialFunctionNested() { +// import AsyncId.{await, async} +// async { +// await(1) +// val neg1 = -1 +// val a = await(1) +// val f = { case x => ({case x => neg1 * x}: PartialFunction[Int, Int])(x + a) }: PartialFunction[Int, Int] +// await(f(2)) +// } mustBe -3 +// } @Test def patternMatchingFunction() { import AsyncId.{await, async} -- cgit v1.2.3 From d332b4614dfd07b4fd91576dac3ff3fddd657106 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 10 Apr 2013 16:32:34 +0200 Subject: Scala 2.10.1 compat: apply renaming to originals of TypeTrees --- src/main/scala/scala/async/TransformUtils.scala | 7 +++++ src/test/scala/scala/async/TreeInterrogation.scala | 4 ++- src/test/scala/scala/async/run/match0/Match0.scala | 35 +++++++++++----------- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/main/scala/scala/async/TransformUtils.scala b/src/main/scala/scala/async/TransformUtils.scala index db82ed6..434d6fd 100644 --- a/src/main/scala/scala/async/TransformUtils.scala +++ b/src/main/scala/scala/async/TransformUtils.scala @@ -58,6 +58,13 @@ private[async] final case class TransformUtils[C <: Context](c: C) { val renamer = new Transformer { override def transform(tree: Tree) = tree match { case Ident(_) => (renameMap get tree.symbol).fold(tree)(Ident(_)) + case tt: TypeTree if tt.original != EmptyTree && tt.original != null => + // We also have to apply our renaming transform on originals of TypeTrees. + // TODO 2.10.1 Can we find a cleaner way? + val symTab = c.universe.asInstanceOf[reflect.internal.SymbolTable] + val tt1 = tt.asInstanceOf[symTab.TypeTree] + tt1.setOriginal(transform(tt.original).asInstanceOf[symTab.Tree]) + super.transform(tree) case _ => super.transform(tree) } } diff --git a/src/test/scala/scala/async/TreeInterrogation.scala b/src/test/scala/scala/async/TreeInterrogation.scala index 2bc4770..4d611e5 100644 --- a/src/test/scala/scala/async/TreeInterrogation.scala +++ b/src/test/scala/scala/async/TreeInterrogation.scala @@ -69,8 +69,10 @@ object TreeInterrogation extends App { withDebug { val cm = reflect.runtime.currentMirror val tb = mkToolbox("-cp target/scala-2.10/classes -Xprint:flatten") + import scala.async.Async._ val tree = tb.parse( - """ async { + """ import scala.async.AsyncId._ + | async { | val x = 1 | val opt = Some("") | await(0) diff --git a/src/test/scala/scala/async/run/match0/Match0.scala b/src/test/scala/scala/async/run/match0/Match0.scala index 79a4e35..7624838 100644 --- a/src/test/scala/scala/async/run/match0/Match0.scala +++ b/src/test/scala/scala/async/run/match0/Match0.scala @@ -83,24 +83,23 @@ class MatchSpec { result mustBe (2) } -// TODO 2.10.1 -// @Test def `support await referring to pattern matching vals`() { -// import AsyncId.{async, await} -// val result = async { -// val x = 1 -// val opt = Some("") -// await(0) -// val o @ Some(y) = opt -// -// { -// val o @ Some(y) = Some(".") -// } -// -// await(0) -// await((o, y.isEmpty)) -// } -// result mustBe ((Some(""), true)) -// } + @Test def `support await referring to pattern matching vals`() { + import AsyncId.{async, await} + val result = async { + val x = 1 + val opt = Some("") + await(0) + val o @ Some(y) = opt + + { + val o @ Some(y) = Some(".") + } + + await(0) + await((o, y.isEmpty)) + } + result mustBe ((Some(""), true)) + } @Test def `await in scrutinee`() { import AsyncId.{async, await} -- cgit v1.2.3 From b60346cda87a4b2213d9b779ed4c6241f126647d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 10 Apr 2013 17:24:09 +0200 Subject: Scala 2.10.1 compat: account for change in PartialFunction synthesis. Since SI-6187, the default case of a partial function is now included in the tree. Before, it was a tree attachment, conditionally inserted in the pattern matcher. I had hoped that that change would allow us to do away with `RestorePatternMatchingFunctions` altogether, but it seems that we aren't so lucky. Instead, I've adapted that transformer to account for the new scheme. --- src/main/scala/scala/async/TransformUtils.scala | 10 +++++- .../scala/async/run/toughtype/ToughType.scala | 40 ++++++++++------------ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/main/scala/scala/async/TransformUtils.scala b/src/main/scala/scala/async/TransformUtils.scala index 434d6fd..38c33a4 100644 --- a/src/main/scala/scala/async/TransformUtils.scala +++ b/src/main/scala/scala/async/TransformUtils.scala @@ -274,18 +274,26 @@ private[async] final case class TransformUtils[C <: Context](c: C) { private object RestorePatternMatchingFunctions extends Transformer { import language.existentials + val DefaultCaseName: TermName = "defaultCase$" override def transform(tree: Tree): Tree = { val SYNTHETIC = (1 << 21).toLong.asInstanceOf[FlagSet] def isSynthetic(cd: ClassDef) = cd.mods hasFlag SYNTHETIC + /** Is this pattern node a synthetic catch-all case, added during PartialFuction synthesis before we know + * whether the user provided cases are exhaustive. */ + def isSyntheticDefaultCase(cdef: CaseDef) = cdef match { + case CaseDef(Bind(DefaultCaseName, _), EmptyTree, _) => true + case _ => false + } tree match { case Block( (cd@ClassDef(_, _, _, Template(_, _, body))) :: Nil, Apply(Select(New(a), nme.CONSTRUCTOR), Nil)) if isSynthetic(cd) => val restored = (body collectFirst { case DefDef(_, /*name.apply | */ name.applyOrElse, _, _, _, Match(_, cases)) => - val transformedCases = super.transformStats(cases, currentOwner).asInstanceOf[List[CaseDef]] + val nonSyntheticCases = cases.takeWhile(cdef => !isSyntheticDefaultCase(cdef)) + val transformedCases = super.transformStats(nonSyntheticCases, currentOwner).asInstanceOf[List[CaseDef]] Match(EmptyTree, transformedCases) }).getOrElse(c.abort(tree.pos, s"Internal Error: Unable to find original pattern matching cases in: $body")) restored diff --git a/src/test/scala/scala/async/run/toughtype/ToughType.scala b/src/test/scala/scala/async/run/toughtype/ToughType.scala index ab0b60d..83f5a2d 100644 --- a/src/test/scala/scala/async/run/toughtype/ToughType.scala +++ b/src/test/scala/scala/async/run/toughtype/ToughType.scala @@ -37,28 +37,26 @@ class ToughTypeSpec { res._1 mustBe (Nil) } -// TODO 2.10.1 -// @Test def patternMatchingPartialFunction() { -// import AsyncId.{await, async} -// async { -// await(1) -// val a = await(1) -// val f = { case x => x + a }: PartialFunction[Int, Int] -// await(f(2)) -// } mustBe 3 -// } + @Test def patternMatchingPartialFunction() { + import AsyncId.{await, async} + async { + await(1) + val a = await(1) + val f = { case x => x + a }: PartialFunction[Int, Int] + await(f(2)) + } mustBe 3 + } -// TODO 2.10.1 -// @Test def patternMatchingPartialFunctionNested() { -// import AsyncId.{await, async} -// async { -// await(1) -// val neg1 = -1 -// val a = await(1) -// val f = { case x => ({case x => neg1 * x}: PartialFunction[Int, Int])(x + a) }: PartialFunction[Int, Int] -// await(f(2)) -// } mustBe -3 -// } + @Test def patternMatchingPartialFunctionNested() { + import AsyncId.{await, async} + async { + await(1) + val neg1 = -1 + val a = await(1) + val f = { case x => ({case x => neg1 * x}: PartialFunction[Int, Int])(x + a) }: PartialFunction[Int, Int] + await(f(2)) + } mustBe -3 + } @Test def patternMatchingFunction() { import AsyncId.{await, async} -- cgit v1.2.3 From 74beb1b751f6abf1775d6a8ec3eea4d63f3fd41f Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 10 Apr 2013 17:55:27 +0200 Subject: Scala 2.10.1 compat: apply renaming to originals of TypeTrees This time in the ANF/Inline transformation. --- src/main/scala/scala/async/AnfTransform.scala | 5 ++++ .../scala/async/run/anf/AnfTransformSpec.scala | 35 +++++++++++----------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/scala/scala/async/AnfTransform.scala b/src/main/scala/scala/async/AnfTransform.scala index afcf6bd..c5fbfd7 100644 --- a/src/main/scala/scala/async/AnfTransform.scala +++ b/src/main/scala/scala/async/AnfTransform.scala @@ -88,6 +88,11 @@ private[async] final case class AnfTransform[C <: Context](c: C) { if (renamed(tree.symbol)) { treeCopy.Select(tree, transform(fun), tree.symbol.name) } else super.transform(tree) + case tt: TypeTree => + val tt1 = tt.asInstanceOf[symtab.TypeTree] + val orig = tt1.original + if (orig != null) tt1.setOriginal(transform(orig.asInstanceOf[Tree]).asInstanceOf[symtab.Tree]) + super.transform(tt) case _ => super.transform(tree) } } diff --git a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala index 03db205..41c13e0 100644 --- a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala +++ b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala @@ -112,24 +112,23 @@ class AnfTransformSpec { State.result mustBe (14) } -// TODO 2.10.1 -// @Test -// def `inlining block does not produce duplicate definition`() { -// import scala.async.AsyncId -// -// AsyncId.async { -// val f = 12 -// val x = AsyncId.await(f) -// -// { -// type X = Int -// val x: X = 42 -// println(x) -// } -// type X = Int -// x: X -// } -// } + @Test + def `inlining block does not produce duplicate definition`() { + import scala.async.AsyncId + + AsyncId.async { + val f = 12 + val x = AsyncId.await(f) + + { + type X = Int + val x: X = 42 + println(x) + } + type X = Int + x: X + } + } @Test def `inlining block in tail position does not produce duplicate definition`() { -- cgit v1.2.3 From e0b32253af62a1bc0ce68ccd7b9a8bc8cf54e3d0 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 11 Apr 2013 23:21:27 +0200 Subject: Avoid needless Unit literal as the expression of a Block. We've got a perfectly good expression at hand. --- src/main/scala/scala/async/ExprBuilder.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scala/async/ExprBuilder.scala b/src/main/scala/scala/async/ExprBuilder.scala index adb6b3d..ca46a83 100644 --- a/src/main/scala/scala/async/ExprBuilder.scala +++ b/src/main/scala/scala/async/ExprBuilder.scala @@ -94,7 +94,7 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c: c.Expr[scala.util.Try[T]]( TypeApply(Select(Ident(name.tr), newTermName("asInstanceOf")), List(TypeTree(weakTypeOf[scala.util.Try[T]]))))).tree, - Block(List(tryGetTree, mkStateTree(nextState), mkResumeApply), c.literalUnit.tree) + Block(List(tryGetTree, mkStateTree(nextState)), mkResumeApply) ) Some(mkHandlerCase(state, List(ifIsFailureTree))) -- cgit v1.2.3