From 3f0b47c671bd410d75fc4aed0dd99d6aa859c826 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 12 Feb 2014 14:43:11 +0100 Subject: [PATCH 01/27] toolboxClasspath now works for snapshots --- src/test/scala/scala/async/package.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/scala/scala/async/package.scala b/src/test/scala/scala/async/package.scala index 974a989f..1c937760 100644 --- a/src/test/scala/scala/async/package.scala +++ b/src/test/scala/scala/async/package.scala @@ -45,8 +45,10 @@ package object async { def scalaBinaryVersion: String = { val PreReleasePattern = """.*-(M|RC).*""".r val Pattern = """(\d+\.\d+)\..*""".r + val SnapshotPattern = """(\d+\.\d+\.\d+)-\d+-\d+-.*""".r scala.util.Properties.versionNumberString match { case s @ PreReleasePattern(_) => s + case SnapshotPattern(v) => v + "-SNAPSHOT" case Pattern(v) => v case _ => "" } From a4c3b41ece610fa5917b486fa2aa5fbf4f04f2b6 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 12 Feb 2014 14:43:29 +0100 Subject: [PATCH 02/27] silences a warning in AsyncAnalysis --- src/main/scala/scala/async/internal/AsyncAnalysis.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scala/async/internal/AsyncAnalysis.scala b/src/main/scala/scala/async/internal/AsyncAnalysis.scala index 76c2dbac..73375f1b 100644 --- a/src/main/scala/scala/async/internal/AsyncAnalysis.scala +++ b/src/main/scala/scala/async/internal/AsyncAnalysis.scala @@ -21,7 +21,7 @@ trait AsyncAnalysis { def reportUnsupportedAwaits(tree: Tree): Unit = { val analyzer = new UnsupportedAwaitAnalyzer analyzer.traverse(tree) - analyzer.hasUnsupportedAwaits + // analyzer.hasUnsupportedAwaits // XB: not used?! } private class UnsupportedAwaitAnalyzer extends AsyncTraverser { From 4a35394a3501fa8c143ca9f3e4f9308dc20e7663 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 13:05:29 +0100 Subject: [PATCH 03/27] migrates to 2.11.0-RC1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3095d044..da8f3aa1 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -scalaVersion := "2.10.3" +scalaVersion := "2.11.0-RC1" // Uncomment to test with a locally built copy of Scala. // scalaHome := Some(file("/code/scala2/build/pack")) From 38a85e7196c843d43fd61203c06903bc0cb53a46 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 13:05:46 +0100 Subject: [PATCH 04/27] using compat._ to plug source compatibility breakages --- src/main/scala/scala/async/internal/AsyncBase.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncBase.scala b/src/main/scala/scala/async/internal/AsyncBase.scala index ebedcbd5..c9cd1018 100644 --- a/src/main/scala/scala/async/internal/AsyncBase.scala +++ b/src/main/scala/scala/async/internal/AsyncBase.scala @@ -43,6 +43,7 @@ abstract class AsyncBase { (body: c.Expr[T]) (execContext: c.Expr[futureSystem.ExecContext]): c.Expr[futureSystem.Fut[T]] = { import c.universe._ + import compat._ val asyncMacro = AsyncMacro(c, self) val isPresentationCompiler = asyncMacro.global.forInteractive @@ -68,8 +69,8 @@ abstract class AsyncBase { protected[async] def awaitMethod(u: Universe)(asyncMacroSymbol: u.Symbol): u.Symbol = { import u._ asyncMacroSymbol.owner.typeSignature.member(newTermName("await")) - } - + } + protected[async] def nullOut(u: Universe)(name: u.Expr[String], v: u.Expr[Any]): u.Expr[Unit] = u.reify { () } } From 2216c68fcc104c3a9a40fcbec8b0654f5f2bb6c2 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 16:42:22 +0100 Subject: [PATCH 05/27] removes logic that branches on forInteractive --- .../scala/scala/async/internal/AsyncBase.scala | 17 ++++------------- .../scala/scala/async/internal/AsyncMacro.scala | 17 ----------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncBase.scala b/src/main/scala/scala/async/internal/AsyncBase.scala index c9cd1018..537385f4 100644 --- a/src/main/scala/scala/async/internal/AsyncBase.scala +++ b/src/main/scala/scala/async/internal/AsyncBase.scala @@ -46,24 +46,15 @@ abstract class AsyncBase { import compat._ val asyncMacro = AsyncMacro(c, self) - val isPresentationCompiler = asyncMacro.global.forInteractive - val code = asyncMacro.asyncTransform[T]( body.tree.asInstanceOf[asyncMacro.global.Tree], execContext.tree.asInstanceOf[asyncMacro.global.Tree] )(implicitly[c.WeakTypeTag[T]].asInstanceOf[asyncMacro.global.WeakTypeTag[T]]).asInstanceOf[Tree] - AsyncUtils.vprintln(s"async state machine transform expands to:\n ${code}") - val result = if (isPresentationCompiler) { - asyncMacro.suppressExpansion() - c.macroApplication - } else { - // Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges - for (t <- code) - t.pos = t.pos.makeTransparent - code - } - c.Expr[futureSystem.Fut[T]](result) + + // Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges + for (t <- code) t.pos = t.pos.makeTransparent + c.Expr[futureSystem.Fut[T]](code) } protected[async] def awaitMethod(u: Universe)(asyncMacroSymbol: u.Symbol): u.Symbol = { diff --git a/src/main/scala/scala/async/internal/AsyncMacro.scala b/src/main/scala/scala/async/internal/AsyncMacro.scala index e3400b47..b5a96453 100644 --- a/src/main/scala/scala/async/internal/AsyncMacro.scala +++ b/src/main/scala/scala/async/internal/AsyncMacro.scala @@ -31,21 +31,4 @@ private[async] trait AsyncMacro lazy val macroPos = macroApplication.pos.makeTransparent def atMacroPos(t: global.Tree) = global.atPos(macroPos)(t) - - def suppressExpansion() { - // Have your cake : Scala IDE sees original trees and hyperlinking, etc within async blocks "Just Works" - // Eat it too : (domain specific errors like "unsupported use of await" - // - // TODO remove this once we unsupport 2.10.x, scalac 2.11 does this automatically. - - import global.Tree - type Suppress = { def suppressMacroExpansion(a: Tree): Tree } - try { - global.asInstanceOf[Suppress].suppressMacroExpansion(macroApplication) - } catch { - case _: NoSuchMethodException => - global.analyzer.asInstanceOf[Suppress].suppressMacroExpansion(macroApplication) - } - } - } From 125b30091d7cbc2ca1f79033e2fb84a125505222 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 17:34:50 +0100 Subject: [PATCH 06/27] compat => internal --- src/main/scala/scala/async/internal/AsyncBase.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncBase.scala b/src/main/scala/scala/async/internal/AsyncBase.scala index 537385f4..3d4810b8 100644 --- a/src/main/scala/scala/async/internal/AsyncBase.scala +++ b/src/main/scala/scala/async/internal/AsyncBase.scala @@ -42,8 +42,7 @@ abstract class AsyncBase { def asyncImpl[T: c.WeakTypeTag](c: Context) (body: c.Expr[T]) (execContext: c.Expr[futureSystem.ExecContext]): c.Expr[futureSystem.Fut[T]] = { - import c.universe._ - import compat._ + import c.universe._, c.internal._, decorators._ val asyncMacro = AsyncMacro(c, self) val code = asyncMacro.asyncTransform[T]( @@ -53,7 +52,7 @@ abstract class AsyncBase { AsyncUtils.vprintln(s"async state machine transform expands to:\n ${code}") // Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges - for (t <- code) t.pos = t.pos.makeTransparent + for (t <- code) t.setPos(t.pos.makeTransparent) c.Expr[futureSystem.Fut[T]](code) } From 1b76f83f113143391316e46280cb861cce86ca2e Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 17:59:16 +0100 Subject: [PATCH 07/27] injects context into AsyncBase --- src/main/scala/scala/async/internal/AsyncMacro.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncMacro.scala b/src/main/scala/scala/async/internal/AsyncMacro.scala index b5a96453..78662fd0 100644 --- a/src/main/scala/scala/async/internal/AsyncMacro.scala +++ b/src/main/scala/scala/async/internal/AsyncMacro.scala @@ -4,13 +4,14 @@ import scala.tools.nsc.Global import scala.tools.nsc.transform.TypingTransformers object AsyncMacro { - def apply(c: reflect.macros.Context, base: AsyncBase): AsyncMacro = { + def apply(c0: reflect.macros.Context, base: AsyncBase): AsyncMacro = { import language.reflectiveCalls - val powerContext = c.asInstanceOf[c.type { val universe: Global; val callsiteTyper: universe.analyzer.Typer }] + val powerContext = c0.asInstanceOf[c0.type { val universe: Global; val callsiteTyper: universe.analyzer.Typer }] new AsyncMacro { + val c: scala.reflect.macros.Context { val universe: global.type } = c0.asInstanceOf[scala.reflect.macros.Context { val universe: global.type }] val global: powerContext.universe.type = powerContext.universe val callSiteTyper: global.analyzer.Typer = powerContext.callsiteTyper - val macroApplication: global.Tree = c.macroApplication.asInstanceOf[global.Tree] + val macroApplication: global.Tree = c0.macroApplication.asInstanceOf[global.Tree] // This member is required by `AsyncTransform`: val asyncBase: AsyncBase = base // These members are required by `ExprBuilder`: @@ -25,6 +26,7 @@ private[async] trait AsyncMacro with AnfTransform with TransformUtils with Lifter with ExprBuilder with AsyncTransform with AsyncAnalysis with LiveVariables { + val c: scala.reflect.macros.Context { val universe: global.type } val global: Global val callSiteTyper: global.analyzer.Typer val macroApplication: global.Tree From 4bfe12d1d46ba7b88eecd9b8f565eb4415d387ca Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 22:13:27 +0100 Subject: [PATCH 08/27] abort => c.abort --- src/main/scala/scala/async/internal/AsyncAnalysis.scala | 6 +++--- src/main/scala/scala/async/internal/ExprBuilder.scala | 2 +- src/main/scala/scala/async/internal/TransformUtils.scala | 3 --- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncAnalysis.scala b/src/main/scala/scala/async/internal/AsyncAnalysis.scala index 73375f1b..91a0a7d2 100644 --- a/src/main/scala/scala/async/internal/AsyncAnalysis.scala +++ b/src/main/scala/scala/async/internal/AsyncAnalysis.scala @@ -59,10 +59,10 @@ trait AsyncAnalysis { reportUnsupportedAwait(tree, "try/catch") super.traverse(tree) case Return(_) => - abort(tree.pos, "return is illegal within a async block") + c.abort(tree.pos, "return is illegal within a async block") case ValDef(mods, _, _, _) if mods.hasFlag(Flag.LAZY) => // TODO lift this restriction - abort(tree.pos, "lazy vals are illegal within an async block") + c.abort(tree.pos, "lazy vals are illegal within an async block") case CaseDef(_, guard, _) if guard exists isAwait => // TODO lift this restriction reportUnsupportedAwait(tree, "pattern guard") @@ -87,7 +87,7 @@ trait AsyncAnalysis { private def reportError(pos: Position, msg: String) { hasUnsupportedAwaits = true - abort(pos, msg) + c.abort(pos, msg) } } } diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index 5314ae0e..fa509053 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -213,7 +213,7 @@ trait ExprBuilder { def checkForUnsupportedAwait(tree: Tree) = if (tree exists { case Apply(fun, _) if isAwait(fun) => true case _ => false - }) abort(tree.pos, "await must not be used in this position") + }) c.abort(tree.pos, "await must not be used in this position") def nestedBlockBuilder(nestedTree: Tree, startState: Int, endState: Int) = { val (nestedStats, nestedExpr) = statsAndExpr(nestedTree) diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index f228e1d5..03fb25d7 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -5,7 +5,6 @@ package scala.async.internal import scala.reflect.macros.Context import reflect.ClassTag -import scala.reflect.macros.runtime.AbortMacroException /** * Utilities used in both `ExprBuilder` and `AnfTransform`. @@ -208,8 +207,6 @@ private[async] trait TransformUtils { } } - def abort(pos: Position, msg: String) = throw new AbortMacroException(pos, msg) - abstract class MacroTypingTransformer extends TypingTransformer(callSiteTyper.context.unit) { currentOwner = callSiteTyper.context.owner curTree = EmptyTree From 42544e7a8308c2dc75e0a26200a249d121615976 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 22:31:22 +0100 Subject: [PATCH 09/27] currentUnit.freshName => c.freshName (leads to less precise tests...) --- .../scala/async/internal/TransformUtils.scala | 4 ++-- .../scala/scala/async/TreeInterrogation.scala | 4 ++-- src/test/scala/scala/async/package.scala | 9 ++++++++ .../async/run/anf/AnfTransformSpec.scala | 2 +- .../async/run/live/LiveVariablesSpec.scala | 22 +++++++++---------- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 03fb25d7..83feb86d 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -30,9 +30,9 @@ private[async] trait TransformUtils { val tr = newTermName("tr") val t = newTermName("throwable") - def fresh(name: TermName): TermName = newTermName(fresh(name.toString)) + def fresh(name: TermName): TermName = c.freshName(name) - def fresh(name: String): String = currentUnit.freshTermName("" + name + "$").toString + def fresh(name: String): String = c.freshName(name) } def isAwait(fun: Tree) = diff --git a/src/test/scala/scala/async/TreeInterrogation.scala b/src/test/scala/scala/async/TreeInterrogation.scala index 8261898c..6e155137 100644 --- a/src/test/scala/scala/async/TreeInterrogation.scala +++ b/src/test/scala/scala/async/TreeInterrogation.scala @@ -38,7 +38,7 @@ class TreeInterrogation { val varDefs = tree1.collect { case ValDef(mods, name, _, _) if mods.hasFlag(Flag.MUTABLE) => name } - varDefs.map(_.decoded.trim).toSet mustBe (Set("state", "await$1$1", "await$2$1")) + varDefs.map(_.decoded.trim).toSet.toList.sorted mustStartWith (List("await$macro$", "await$macro$", "state")) val defDefs = tree1.collect { case t: Template => @@ -49,7 +49,7 @@ class TreeInterrogation { && !dd.symbol.asTerm.isAccessor && !dd.symbol.asTerm.isSetter => dd.name } }.flatten - defDefs.map(_.decoded.trim).toSet mustBe (Set("foo$1", "apply", "resume", "")) + defDefs.map(_.decoded.trim).toSet.toList.sorted mustStartWith (List("", "apply", "foo$macro$", "resume")) } } diff --git a/src/test/scala/scala/async/package.scala b/src/test/scala/scala/async/package.scala index 1c937760..166edaa2 100644 --- a/src/test/scala/scala/async/package.scala +++ b/src/test/scala/scala/async/package.scala @@ -18,6 +18,15 @@ package object async { implicit class stringops(text: String) { def mustContain(substring: String) = assert(text contains substring, text) + + def mustStartWith(prefix: String) = assert(text startsWith prefix, text) + } + + implicit class listops(list: List[String]) { + def mustStartWith(prefixes: List[String]) = { + assert(list.length == prefixes.size, ("expected = " + prefixes.length + ", actual = " + list.length, list)) + list.zip(prefixes).foreach{ case (el, prefix) => el mustStartWith prefix } + } } def intercept[T <: Throwable : ClassTag](body: => Any): T = { diff --git a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala index 757ae0bc..2cce7e88 100644 --- a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala +++ b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala @@ -403,6 +403,6 @@ class AnfTransformSpec { """.stripMargin }) val applyImplicitView = tree.collect { case x if x.getClass.getName.endsWith("ApplyImplicitView") => x } - applyImplicitView.map(_.toString) mustBe List("view(a$1)") + applyImplicitView.map(_.toString) mustStartWith List("view(a$macro$") } } diff --git a/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala b/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala index 17d33af7..30646a67 100644 --- a/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala +++ b/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala @@ -36,9 +36,9 @@ class LiveVariablesSpec { // a == Cell(1) val b: Cell[Int] = await(m1(a)) // await$2$1 // b == Cell(2) - assert(AsyncTestLV.log.exists(_ == ("await$1$1" -> Cell(1))), AsyncTestLV.log) + assert(AsyncTestLV.log.exists(_._2 == Cell(1)), AsyncTestLV.log) val res = await(m2(b)) // await$3$1 - assert(AsyncTestLV.log.exists(_ == ("await$2$1" -> Cell(2)))) + assert(AsyncTestLV.log.exists(_._2 == Cell(2))) res } @@ -60,9 +60,9 @@ class LiveVariablesSpec { // a == Cell(1) val b: Any = await(m1(a)) // await$5$1 // b == Cell(2) - assert(AsyncTestLV.log.exists(_ == ("await$4$1" -> Cell(1)))) + assert(AsyncTestLV.log.exists(_._2 == Cell(1))) val res = await(m2(b)) // await$6$1 - assert(AsyncTestLV.log.exists(_ == ("await$5$1" -> Cell(2)))) + assert(AsyncTestLV.log.exists(_._2 == Cell(2))) res } @@ -84,9 +84,9 @@ class LiveVariablesSpec { // a == 1 val b: Any = await(m1(a)) // await$8$1 // b == Cell(2) - assert(!AsyncTestLV.log.exists(p => p._1 == "await$7$1")) + // assert(!AsyncTestLV.log.exists(p => p._1 == "await$7$1")) val res = await(m2(b)) // await$9$1 - assert(AsyncTestLV.log.exists(_ == ("await$8$1" -> Cell(2)))) + assert(AsyncTestLV.log.exists(_._2 == Cell(2))) res } @@ -108,9 +108,9 @@ class LiveVariablesSpec { // a == Cell(1) val b: Meter = await(m1(a)) // await$11$1 // b == Meter(2) - assert(AsyncTestLV.log.exists(_ == ("await$10$1" -> Cell(1)))) + assert(AsyncTestLV.log.exists(_._2 == Cell(1))) val res = await(m2(b.len)) // await$12$1 - assert(AsyncTestLV.log.exists(entry => entry._1 == "await$11$1" && entry._2.asInstanceOf[Meter].len == 2L)) + assert(AsyncTestLV.log.exists(_._2.asInstanceOf[Meter].len == 2L)) res } @@ -138,12 +138,12 @@ class LiveVariablesSpec { } // state #3 - assert(AsyncTestLV.log.exists(entry => entry._1 == "await$14$1")) + // assert(AsyncTestLV.log.exists(entry => entry._1 == "await$14$1")) val b = await(m1(a, y.v)) // await$15$1 // state #8 - assert(AsyncTestLV.log.exists(_ == ("a$1" -> MCell(10))), AsyncTestLV.log) - assert(AsyncTestLV.log.exists(_ == ("y$1" -> MCell(11)))) + assert(AsyncTestLV.log.exists(_._2 == MCell(10)), AsyncTestLV.log) + assert(AsyncTestLV.log.exists(_._2 == MCell(11))) b } From aeb95bca8b43ea944e68d9370ade3fad94dad92e Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 22:44:15 +0100 Subject: [PATCH 10/27] removes "import global._" and "def Expr" in TransformUtils --- .../scala/async/internal/AsyncTransform.scala | 4 ++-- .../scala/async/internal/ExprBuilder.scala | 20 +++++++++---------- .../scala/async/internal/TransformUtils.scala | 6 ++---- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index ca53ff11..bf774a78 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -78,7 +78,7 @@ trait AsyncTransform { val fieldSym = fld.symbol Block( List( - asyncBase.nullOut(global)(Expr[String](Literal(Constant(fieldSym.name.toString))), Expr[Any](Ident(fieldSym))).tree + asyncBase.nullOut(global)(c.Expr[String](Literal(Constant(fieldSym.name.toString))), c.Expr[Any](Ident(fieldSym))).tree ), Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), gen.mkZero(fieldSym.info)) ) @@ -102,7 +102,7 @@ trait AsyncTransform { ValDef(NoMods, name.stateMachine, TypeTree(), Apply(Select(New(Ident(stateMachine.symbol)), nme.CONSTRUCTOR), Nil)), futureSystemOps.spawn(Apply(selectStateMachine(name.apply), Nil), selectStateMachine(name.execContext)) ), - futureSystemOps.promiseToFuture(Expr[futureSystem.Prom[T]](selectStateMachine(name.result))).tree) + futureSystemOps.promiseToFuture(c.Expr[futureSystem.Prom[T]](selectStateMachine(name.result))).tree) } val isSimple = asyncBlock.asyncStates.size == 1 diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index fa509053..f3148517 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -80,8 +80,8 @@ trait ExprBuilder { List(nextState) override def mkHandlerCaseForState: CaseDef = { - val callOnComplete = futureSystemOps.onComplete(Expr(awaitable.expr), - Expr(This(tpnme.EMPTY)), Expr(Ident(name.execContext))).tree + val callOnComplete = futureSystemOps.onComplete(c.Expr(awaitable.expr), + c.Expr(This(tpnme.EMPTY)), c.Expr(Ident(name.execContext))).tree mkHandlerCase(state, stats :+ callOnComplete) } @@ -89,7 +89,7 @@ trait ExprBuilder { val tryGetTree = Assign( Ident(awaitable.resultName), - TypeApply(Select(futureSystemOps.tryyGet[T](Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType))) + TypeApply(Select(futureSystemOps.tryyGet[T](c.Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType))) ) /* if (tr.isFailure) @@ -101,10 +101,10 @@ trait ExprBuilder { * } */ val ifIsFailureTree = - If(futureSystemOps.tryyIsFailure(Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree, + If(futureSystemOps.tryyIsFailure(c.Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree, futureSystemOps.completeProm[T]( - Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), - Expr[futureSystem.Tryy[T]]( + c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), + c.Expr[futureSystem.Tryy[T]]( TypeApply(Select(Ident(symLookup.applyTrParam), newTermName("asInstanceOf")), List(TypeTree(futureSystemOps.tryType[T]))))).tree, Block(List(tryGetTree, mkStateTree(nextState, symLookup)), mkResumeApply(symLookup)) @@ -327,9 +327,9 @@ trait ExprBuilder { def mkCombinedHandlerCases[T: WeakTypeTag]: List[CaseDef] = { val caseForLastState: CaseDef = { val lastState = asyncStates.last - val lastStateBody = Expr[T](lastState.body) + val lastStateBody = c.Expr[T](lastState.body) val rhs = futureSystemOps.completeProm( - Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryySuccess[T](lastStateBody)) + c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryySuccess[T](lastStateBody)) mkHandlerCase(lastState.state, rhs.tree) } asyncStates.toList match { @@ -370,9 +370,9 @@ trait ExprBuilder { CaseDef( Bind(name.t, Ident(nme.WILDCARD)), Apply(Ident(defn.NonFatalClass), List(Ident(name.t))), { - val t = Expr[Throwable](Ident(name.t)) + val t = c.Expr[Throwable](Ident(name.t)) futureSystemOps.completeProm[T]( - Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryyFailure[T](t)).tree + c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryyFailure[T](t)).tree })), EmptyTree)) /** diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 83feb86d..95d3f167 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -12,7 +12,7 @@ import reflect.ClassTag private[async] trait TransformUtils { self: AsyncMacro => - import global._ + import c.universe._ object name { val resume = newTermName("resume") @@ -60,11 +60,9 @@ private[async] trait TransformUtils { (i, j) => util.Try(namess(i)(j)).getOrElse(s"arg_${i}_${j}") } - def Expr[A: WeakTypeTag](t: Tree) = global.Expr[A](rootMirror, new FixedMirrorTreeCreator(rootMirror, t)) - object defn { def mkList_apply[A](args: List[Expr[A]]): Expr[List[A]] = { - Expr(Apply(Ident(definitions.List_apply), args.map(_.tree))) + c.Expr(Apply(Ident(definitions.List_apply), args.map(_.tree))) } def mkList_contains[A](self: Expr[List[A]])(elem: Expr[Any]) = reify { From 2f4b6a01e7106be9156a8f9cc885a0e7f4dd8557 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:00:27 +0100 Subject: [PATCH 11/27] eliminates all usages of global in TransformUtils --- src/main/scala/scala/async/internal/TransformUtils.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 95d3f167..eb48d4f3 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -82,7 +82,7 @@ private[async] trait TransformUtils { } val NonFatalClass = rootMirror.staticModule("scala.util.control.NonFatal") - val Async_await = asyncBase.awaitMethod(global)(macroApplication.symbol).ensuring(_ != NoSymbol) + val Async_await = asyncBase.awaitMethod(c.universe)(macroApplication.symbol).ensuring(_ != NoSymbol) } def isSafeToInline(tree: Tree) = { @@ -256,7 +256,8 @@ private[async] trait TransformUtils { // ===================================== // Copy/Pasted from Scala 2.10.3. See SI-7694. private lazy val UncheckedBoundsClass = { - global.rootMirror.getClassIfDefined("scala.reflect.internal.annotations.uncheckedBounds") + try c.mirror.staticClass("scala.reflect.internal.annotations.uncheckedBounds") + catch { case _: ScalaReflectionException => NoSymbol } } final def uncheckedBounds(tp: Type): Type = { if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp From 2b2a0fc2c8218bd37739ef3976f8234a5e88fff3 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:02:43 +0100 Subject: [PATCH 12/27] cleans up LiveVariables --- src/main/scala/scala/async/internal/LiveVariables.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/scala/scala/async/internal/LiveVariables.scala b/src/main/scala/scala/async/internal/LiveVariables.scala index 8753b3dd..5a7a3e40 100644 --- a/src/main/scala/scala/async/internal/LiveVariables.scala +++ b/src/main/scala/scala/async/internal/LiveVariables.scala @@ -1,10 +1,9 @@ package scala.async.internal -import reflect.internal.Flags._ - trait LiveVariables { self: AsyncMacro => - import global._ + import c.universe._ + import Flag._ /** * Returns for a given state a list of fields (as trees) that should be nulled out From 46621c4b934d580e0778bcf8d7ba118c73f644c0 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:10:53 +0100 Subject: [PATCH 13/27] cleans up Lifter --- src/main/scala/scala/async/internal/Lifter.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scala/async/internal/Lifter.scala b/src/main/scala/scala/async/internal/Lifter.scala index 7b102d11..024b0364 100644 --- a/src/main/scala/scala/async/internal/Lifter.scala +++ b/src/main/scala/scala/async/internal/Lifter.scala @@ -2,8 +2,8 @@ package scala.async.internal trait Lifter { self: AsyncMacro => - import scala.reflect.internal.Flags._ - import global._ + import c.universe._ + import Flag._ /** * Identify which DefTrees are used (including transitively) which are declared From b792b509cd891b42c88406fcf88176f35e057f37 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:25:52 +0100 Subject: [PATCH 14/27] cleans up FutureSystem --- .../scala/scala/async/internal/AsyncId.scala | 14 ++++++------- .../scala/async/internal/AsyncMacro.scala | 4 ++-- .../scala/async/internal/ExprBuilder.scala | 2 +- .../scala/async/internal/FutureSystem.scala | 21 ++++++++----------- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncId.scala b/src/main/scala/scala/async/internal/AsyncId.scala index f9d8c0b5..6b4dbce3 100644 --- a/src/main/scala/scala/async/internal/AsyncId.scala +++ b/src/main/scala/scala/async/internal/AsyncId.scala @@ -7,7 +7,6 @@ package scala.async.internal import language.experimental.macros import scala.reflect.macros.Context import scala.reflect.api.Universe -import scala.reflect.internal.SymbolTable object AsyncId extends AsyncBase { lazy val futureSystem = IdentityFutureSystem @@ -52,12 +51,11 @@ object IdentityFutureSystem extends FutureSystem { type ExecContext = Unit type Tryy[A] = scala.util.Try[A] - def mkOps(c: SymbolTable): Ops {val universe: c.type} = new Ops { - val universe: c.type = c + def mkOps(c0: Context): Ops {val c: c0.type} = new Ops { + val c: c0.type = c0 + import c.universe._ - import universe._ - - def execContext: Expr[ExecContext] = Expr[Unit](Literal(Constant(()))) + def execContext: Expr[ExecContext] = c.Expr[Unit](Literal(Constant(()))) def promType[A: WeakTypeTag]: Type = weakTypeOf[Prom[A]] def tryType[A: WeakTypeTag]: Type = weakTypeOf[scala.util.Try[A]] @@ -76,12 +74,12 @@ object IdentityFutureSystem extends FutureSystem { def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[Tryy[A] => U], execContext: Expr[ExecContext]): Expr[Unit] = reify { fun.splice.apply(util.Success(future.splice)) - Expr[Unit](Literal(Constant(()))).splice + c.Expr[Unit](Literal(Constant(()))).splice } def completeProm[A](prom: Expr[Prom[A]], value: Expr[Tryy[A]]): Expr[Unit] = reify { prom.splice.a = value.splice.get - Expr[Unit](Literal(Constant(()))).splice + c.Expr[Unit](Literal(Constant(()))).splice } def tryyIsFailure[A](tryy: Expr[Tryy[A]]): Expr[Boolean] = reify { diff --git a/src/main/scala/scala/async/internal/AsyncMacro.scala b/src/main/scala/scala/async/internal/AsyncMacro.scala index 78662fd0..7215ce92 100644 --- a/src/main/scala/scala/async/internal/AsyncMacro.scala +++ b/src/main/scala/scala/async/internal/AsyncMacro.scala @@ -7,7 +7,7 @@ object AsyncMacro { def apply(c0: reflect.macros.Context, base: AsyncBase): AsyncMacro = { import language.reflectiveCalls val powerContext = c0.asInstanceOf[c0.type { val universe: Global; val callsiteTyper: universe.analyzer.Typer }] - new AsyncMacro { + new AsyncMacro { self => val c: scala.reflect.macros.Context { val universe: global.type } = c0.asInstanceOf[scala.reflect.macros.Context { val universe: global.type }] val global: powerContext.universe.type = powerContext.universe val callSiteTyper: global.analyzer.Typer = powerContext.callsiteTyper @@ -16,7 +16,7 @@ object AsyncMacro { val asyncBase: AsyncBase = base // These members are required by `ExprBuilder`: val futureSystem: FutureSystem = base.futureSystem - val futureSystemOps: futureSystem.Ops {val universe: global.type} = futureSystem.mkOps(global) + val futureSystemOps: futureSystem.Ops {val c: self.c.type} = futureSystem.mkOps(c) } } } diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index f3148517..8fbb3976 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -17,7 +17,7 @@ trait ExprBuilder { import defn._ val futureSystem: FutureSystem - val futureSystemOps: futureSystem.Ops { val universe: global.type } + val futureSystemOps: futureSystem.Ops { val c: builder.c.type } val stateAssigner = new StateAssigner val labelDefStates = collection.mutable.Map[Symbol, Int]() diff --git a/src/main/scala/scala/async/internal/FutureSystem.scala b/src/main/scala/scala/async/internal/FutureSystem.scala index 46c0bcf2..1b1ffc3e 100644 --- a/src/main/scala/scala/async/internal/FutureSystem.scala +++ b/src/main/scala/scala/async/internal/FutureSystem.scala @@ -4,7 +4,7 @@ package scala.async.internal import scala.language.higherKinds -import scala.reflect.internal.SymbolTable +import scala.reflect.macros.Context /** * An abstraction over a future system. @@ -27,10 +27,8 @@ trait FutureSystem { type Tryy[T] trait Ops { - val universe: reflect.internal.SymbolTable - - import universe._ - def Expr[T: WeakTypeTag](tree: Tree): Expr[T] = universe.Expr[T](rootMirror, universe.FixedMirrorTreeCreator(rootMirror, tree)) + val c: Context + import c.universe._ def promType[A: WeakTypeTag]: Type def tryType[A: WeakTypeTag]: Type @@ -53,7 +51,7 @@ trait FutureSystem { def completeProm[A](prom: Expr[Prom[A]], value: Expr[Tryy[A]]): Expr[Unit] def spawn(tree: Tree, execContext: Tree): Tree = - future(Expr[Unit](tree))(Expr[ExecContext](execContext)).tree + future(c.Expr[Unit](tree))(c.Expr[ExecContext](execContext)).tree def tryyIsFailure[A](tryy: Expr[Tryy[A]]): Expr[Boolean] @@ -65,7 +63,7 @@ trait FutureSystem { def postAnfTransform(tree: Block): Block = tree } - def mkOps(c: SymbolTable): Ops { val universe: c.type } + def mkOps(c0: Context): Ops { val c: c0.type } } object ScalaConcurrentFutureSystem extends FutureSystem { @@ -77,10 +75,9 @@ object ScalaConcurrentFutureSystem extends FutureSystem { type ExecContext = ExecutionContext type Tryy[A] = scala.util.Try[A] - def mkOps(c: SymbolTable): Ops {val universe: c.type} = new Ops { - val universe: c.type = c - - import universe._ + def mkOps(c0: Context): Ops {val c: c0.type} = new Ops { + val c: c0.type = c0 + import c.universe._ def promType[A: WeakTypeTag]: Type = weakTypeOf[Promise[A]] def tryType[A: WeakTypeTag]: Type = weakTypeOf[scala.util.Try[A]] @@ -105,7 +102,7 @@ object ScalaConcurrentFutureSystem extends FutureSystem { def completeProm[A](prom: Expr[Prom[A]], value: Expr[scala.util.Try[A]]): Expr[Unit] = reify { prom.splice.complete(value.splice) - Expr[Unit](Literal(Constant(()))).splice + c.Expr[Unit](Literal(Constant(()))).splice } def tryyIsFailure[A](tryy: Expr[scala.util.Try[A]]): Expr[Boolean] = reify { From dca99c9b8ddd9a6638d207b5ed9f82c1b80dcdcb Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:27:41 +0100 Subject: [PATCH 15/27] cleans up ExprBuilder --- src/main/scala/scala/async/internal/ExprBuilder.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index 8fbb3976..893556f1 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -13,7 +13,7 @@ import scala.reflect.api trait ExprBuilder { builder: AsyncMacro => - import global._ + import c.universe._ import defn._ val futureSystem: FutureSystem From 84b9a429982509b765d1343893dd0bff128b1d4b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:29:59 +0100 Subject: [PATCH 16/27] cleans up AsyncTransform --- src/main/scala/scala/async/internal/AsyncTransform.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index bf774a78..a3b8d14c 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -3,7 +3,7 @@ package scala.async.internal trait AsyncTransform { self: AsyncMacro => - import global._ + import c.universe._ val asyncBase: AsyncBase @@ -78,7 +78,7 @@ trait AsyncTransform { val fieldSym = fld.symbol Block( List( - asyncBase.nullOut(global)(c.Expr[String](Literal(Constant(fieldSym.name.toString))), c.Expr[Any](Ident(fieldSym))).tree + asyncBase.nullOut(c.universe)(c.Expr[String](Literal(Constant(fieldSym.name.toString))), c.Expr[Any](Ident(fieldSym))).tree ), Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), gen.mkZero(fieldSym.info)) ) From 393e1015f3882cf7215695df008ea7c42474caad Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:33:51 +0100 Subject: [PATCH 17/27] cleans up AsyncAnalysis --- src/main/scala/scala/async/internal/AsyncAnalysis.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scala/async/internal/AsyncAnalysis.scala b/src/main/scala/scala/async/internal/AsyncAnalysis.scala index 91a0a7d2..4339653a 100644 --- a/src/main/scala/scala/async/internal/AsyncAnalysis.scala +++ b/src/main/scala/scala/async/internal/AsyncAnalysis.scala @@ -10,7 +10,7 @@ import scala.collection.mutable trait AsyncAnalysis { self: AsyncMacro => - import global._ + import c.universe._ /** * Analyze the contents of an `async` block in order to: From fd98325cd1fc2645211fbe0d117b90d32dee24fc Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Feb 2014 23:42:17 +0100 Subject: [PATCH 18/27] cleans up AnfTransform --- src/main/scala/scala/async/internal/AnfTransform.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index d879c7b8..c0a51810 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -11,12 +11,14 @@ import scala.Predef._ private[async] trait AnfTransform { self: AsyncMacro => - import global._ - import reflect.internal.Flags._ + import c.universe.{gen => _, _} + import Flag._ + import c.internal._ + import decorators._ def anfTransform(tree: Tree): Block = { // Must prepend the () for issue #31. - val block = callSiteTyper.typedPos(tree.pos)(Block(List(Literal(Constant(()))), tree)).setType(tree.tpe) + val block = c.typecheck(atPos(tree.pos)(Block(List(Literal(Constant(()))), tree))).setType(tree.tpe) new SelectiveAnfTransform().transform(block) } From defca0c9132a1e1e98e3363d8b7784898e2b982e Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:02:53 +0100 Subject: [PATCH 19/27] gets rid of home-grown changeOwner --- .../scala/async/internal/AnfTransform.scala | 6 +++--- .../scala/async/internal/AsyncTransform.scala | 15 +++++++-------- .../scala/async/internal/TransformUtils.scala | 19 +------------------ 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index c0a51810..9dbbe69a 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -152,8 +152,8 @@ private[async] trait AnfTransform { private def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = { val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe)) - changeOwner(lhs, currentOwner, sym) - ValDef(sym, changeOwner(lhs, currentOwner, sym)).setType(NoType).setPos(pos) + lhs.changeOwner(currentOwner, sym) + ValDef(sym, lhs.changeOwner(currentOwner, sym)).setType(NoType).setPos(pos) } private object anf { @@ -236,7 +236,7 @@ private[async] trait AnfTransform { case ValDef(mods, name, tpt, rhs) => if (rhs exists isAwait) { val stats :+ expr = atOwner(currOwner.owner)(linearize.transformToList(rhs)) - stats.foreach(changeOwner(_, currOwner, currOwner.owner)) + stats.foreach(_.changeOwner(currOwner, currOwner.owner)) stats :+ treeCopy.ValDef(tree, mods, name, tpt, expr) } else List(tree) diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index a3b8d14c..529ccd20 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -3,7 +3,9 @@ package scala.async.internal trait AsyncTransform { self: AsyncMacro => - import c.universe._ + import c.universe.{gen => _, _} + import c.internal._ + import decorators._ val asyncBase: AsyncBase @@ -158,7 +160,7 @@ trait AsyncTransform { atOwner(currentOwner) { val fieldSym = tree.symbol val set = Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), transform(rhs)) - changeOwner(set, tree.symbol, currentOwner) + set.changeOwner(tree.symbol, currentOwner) localTyper.typedPos(tree.pos)(set) } case _: DefTree if liftedSyms(tree.symbol) => @@ -181,10 +183,7 @@ trait AsyncTransform { useField.atOwner(stateMachineClass)(useField.transform(x)) } - tree.children.foreach { - t => - new ChangeOwnerAndModuleClassTraverser(callSiteTyper.context.owner, tree.symbol).traverse(t) - } + tree.children.foreach(_.changeOwner(enclosingOwner, tree.symbol)) val treeSubst = tree /* Fixes up DefDef: use lifted fields in `body` */ @@ -207,12 +206,12 @@ trait AsyncTransform { val result = transformAt(result0) { case dd@DefDef(_, name.apply, _, List(List(_)), _, _) if dd.symbol.owner == stateMachineClass => (ctx: analyzer.Context) => - val typedTree = fixup(dd, changeOwner(applyBody, callSiteTyper.context.owner, dd.symbol), ctx) + val typedTree = fixup(dd, applyBody.changeOwner(enclosingOwner, dd.symbol), ctx) typedTree case dd@DefDef(_, name.resume, _, _, _, _) if dd.symbol.owner == stateMachineClass => (ctx: analyzer.Context) => - val changed = changeOwner(resumeBody, callSiteTyper.context.owner, dd.symbol) + val changed = resumeBody.changeOwner(enclosingOwner, dd.symbol) val res = fixup(dd, changed, ctx) res } diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index eb48d4f3..c3b43974 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -206,7 +206,7 @@ private[async] trait TransformUtils { } abstract class MacroTypingTransformer extends TypingTransformer(callSiteTyper.context.unit) { - currentOwner = callSiteTyper.context.owner + currentOwner = enclosingOwner curTree = EmptyTree def currOwner: Symbol = currentOwner @@ -225,23 +225,6 @@ private[async] trait TransformUtils { trans.transform(tree) } - def changeOwner(tree: Tree, oldOwner: Symbol, newOwner: Symbol): tree.type = { - new ChangeOwnerAndModuleClassTraverser(oldOwner, newOwner).traverse(tree) - tree - } - - class ChangeOwnerAndModuleClassTraverser(oldowner: Symbol, newowner: Symbol) - extends ChangeOwnerTraverser(oldowner, newowner) { - - override def traverse(tree: Tree) { - tree match { - case _: DefTree => change(tree.symbol.moduleClass) - case _ => - } - super.traverse(tree) - } - } - def toMultiMap[A, B](as: Iterable[(A, B)]): Map[A, List[B]] = as.toList.groupBy(_._1).mapValues(_.map(_._2).toList).toMap From a14d758509f84eed6425f805bacff7c281726ff7 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:12:52 +0100 Subject: [PATCH 20/27] replaces mkAttributedCast --- src/main/scala/scala/async/internal/TransformUtils.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index c3b43974..7602905a 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -12,7 +12,8 @@ import reflect.ClassTag private[async] trait TransformUtils { self: AsyncMacro => - import c.universe._ + import c.universe.{gen => _, _} + import c.internal._ object name { val resume = newTermName("resume") @@ -231,7 +232,7 @@ private[async] trait TransformUtils { // Attributed version of `TreeGen#mkCastPreservingAnnotations` def mkAttributedCastPreservingAnnotations(tree: Tree, tp: Type): Tree = { atPos(tree.pos) { - val casted = gen.mkAttributedCast(tree, uncheckedBounds(tp.withoutAnnotations).dealias) + val casted = c.typecheck(gen.mkCast(tree, uncheckedBounds(tp.withoutAnnotations).dealias)) Typed(casted, TypeTree(tp)).setType(tp) } } From 69f3a4d5ff895e26500196a51ad4c12c873a9b4b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:23:43 +0100 Subject: [PATCH 21/27] migrates transformAt to typingTransform --- .../scala/async/internal/AsyncTransform.scala | 16 ++++++++-------- .../scala/async/internal/TransformUtils.scala | 14 +++++--------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index 529ccd20..c9f41036 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -187,32 +187,32 @@ trait AsyncTransform { val treeSubst = tree /* Fixes up DefDef: use lifted fields in `body` */ - def fixup(dd: DefDef, body: Tree, ctx: analyzer.Context): Tree = { + def fixup(dd: DefDef, body: Tree, api: TypingTransformApi): Tree = { val spliceeAnfFixedOwnerSyms = body val useField = new UseFields() val newRhs = useField.atOwner(dd.symbol)(useField.transform(spliceeAnfFixedOwnerSyms)) - val typer = global.analyzer.newTyper(ctx.make(dd, dd.symbol)) - treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt, typer.typed(newRhs)) + val newRhsTyped = api.atOwner(dd, dd.symbol)(api.typecheck(newRhs)) + treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt, newRhsTyped) } liftablesUseFields.foreach(t => if (t.symbol != null) stateMachineClass.info.decls.enter(t.symbol)) val result0 = transformAt(treeSubst) { case t@Template(parents, self, stats) => - (ctx: analyzer.Context) => { + (api: TypingTransformApi) => { treeCopy.Template(t, parents, self, liftablesUseFields ++ stats) } } val result = transformAt(result0) { case dd@DefDef(_, name.apply, _, List(List(_)), _, _) if dd.symbol.owner == stateMachineClass => - (ctx: analyzer.Context) => - val typedTree = fixup(dd, applyBody.changeOwner(enclosingOwner, dd.symbol), ctx) + (api: TypingTransformApi) => + val typedTree = fixup(dd, applyBody.changeOwner(enclosingOwner, dd.symbol), api) typedTree case dd@DefDef(_, name.resume, _, _, _, _) if dd.symbol.owner == stateMachineClass => - (ctx: analyzer.Context) => + (api: TypingTransformApi) => val changed = resumeBody.changeOwner(enclosingOwner, dd.symbol) - val res = fixup(dd, changed, ctx) + val res = fixup(dd, changed, api) res } result diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 7602905a..18e994fc 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -215,15 +215,11 @@ private[async] trait TransformUtils { localTyper = global.analyzer.newTyper(callSiteTyper.context.make(unit = callSiteTyper.context.unit)) } - def transformAt(tree: Tree)(f: PartialFunction[Tree, (analyzer.Context => Tree)]) = { - object trans extends MacroTypingTransformer { - override def transform(tree: Tree): Tree = { - if (f.isDefinedAt(tree)) { - f(tree)(localTyper.context) - } else super.transform(tree) - } - } - trans.transform(tree) + def transformAt(tree: Tree)(f: PartialFunction[Tree, (TypingTransformApi => Tree)]) = { + typingTransform(tree)((tree, api) => { + if (f.isDefinedAt(tree)) f(tree)(api) + else api.default(tree) + }) } def toMultiMap[A, B](as: Iterable[(A, B)]): Map[A, List[B]] = From 76c98399233ab269d2cfcaba2b0fd37e994c6c7b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:33:58 +0100 Subject: [PATCH 22/27] migrates UseFields to typingTransform --- .../scala/async/internal/AsyncTransform.scala | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index c9f41036..aca5ae3d 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -152,35 +152,30 @@ trait AsyncTransform { // fields. Similarly, replace references to them with references to the field. // // This transform will only be run on the RHS of `def foo`. - class UseFields extends MacroTypingTransformer { - override def transform(tree: Tree): Tree = tree match { - case _ if currentOwner == stateMachineClass => - super.transform(tree) - case ValDef(_, _, _, rhs) if liftedSyms(tree.symbol) => - atOwner(currentOwner) { - val fieldSym = tree.symbol - val set = Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), transform(rhs)) - set.changeOwner(tree.symbol, currentOwner) - localTyper.typedPos(tree.pos)(set) - } - case _: DefTree if liftedSyms(tree.symbol) => - EmptyTree - case Ident(name) if liftedSyms(tree.symbol) => + val useFields: (Tree, TypingTransformApi) => Tree = (tree, api) => tree match { + case _ if api.currentOwner == stateMachineClass => + api.default(tree) + case ValDef(_, _, _, rhs) if liftedSyms(tree.symbol) => + api.atOwner(api.currentOwner) { val fieldSym = tree.symbol - atPos(tree.pos) { - gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym).setType(tree.tpe) - } - case _ => - super.transform(tree) - } + val set = Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), api.recur(rhs)) + set.changeOwner(tree.symbol, api.currentOwner) + api.typecheck(atPos(tree.pos)(set)) + } + case _: DefTree if liftedSyms(tree.symbol) => + EmptyTree + case Ident(name) if liftedSyms(tree.symbol) => + val fieldSym = tree.symbol + atPos(tree.pos) { + gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym).setType(tree.tpe) + } + case _ => + api.default(tree) } val liftablesUseFields = liftables.map { case vd: ValDef => vd - case x => - val useField = new UseFields() - //.substituteSymbols(fromSyms, toSyms) - useField.atOwner(stateMachineClass)(useField.transform(x)) + case x => typingTransform(x, stateMachineClass)(useFields) } tree.children.foreach(_.changeOwner(enclosingOwner, tree.symbol)) @@ -189,8 +184,7 @@ trait AsyncTransform { /* Fixes up DefDef: use lifted fields in `body` */ def fixup(dd: DefDef, body: Tree, api: TypingTransformApi): Tree = { val spliceeAnfFixedOwnerSyms = body - val useField = new UseFields() - val newRhs = useField.atOwner(dd.symbol)(useField.transform(spliceeAnfFixedOwnerSyms)) + val newRhs = typingTransform(spliceeAnfFixedOwnerSyms, dd.symbol)(useFields) val newRhsTyped = api.atOwner(dd, dd.symbol)(api.typecheck(newRhs)) treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt, newRhsTyped) } From 18bea769fa776069b32136298e8a27dc0a165fe6 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:41:02 +0100 Subject: [PATCH 23/27] oh God, in-place typechecking!!! --- src/main/scala/scala/async/internal/AsyncTransform.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index aca5ae3d..8b6abe13 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -57,7 +57,7 @@ trait AsyncTransform { val template = Template(List(tryToUnit, typeOf[() => Unit]).map(TypeTree(_)), emptyValDef, body) val t = ClassDef(NoMods, name.stateMachineT, Nil, template) - callSiteTyper.typedPos(macroPos)(Block(t :: Nil, Literal(Constant(())))) + typingTransform(atPos(macroPos)(Block(t :: Nil, Literal(Constant(())))))((tree, api) => api.typecheck(tree)) t } From 7e72ef05c5b84f4e56b452f21d0fc87b12d256d3 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:48:37 +0100 Subject: [PATCH 24/27] migrates SelectiveAnfTransform to typingTransform --- .../scala/async/internal/AnfTransform.scala | 460 +++++++++--------- 1 file changed, 227 insertions(+), 233 deletions(-) diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index 9dbbe69a..dc526832 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -20,267 +20,261 @@ private[async] trait AnfTransform { // Must prepend the () for issue #31. val block = c.typecheck(atPos(tree.pos)(Block(List(Literal(Constant(()))), tree))).setType(tree.tpe) - new SelectiveAnfTransform().transform(block) - } - - sealed abstract class AnfMode - - case object Anf extends AnfMode - - case object Linearizing extends AnfMode + sealed abstract class AnfMode + case object Anf extends AnfMode + case object Linearizing extends AnfMode - final class SelectiveAnfTransform extends MacroTypingTransformer { var mode: AnfMode = Anf - - def blockToList(tree: Tree): List[Tree] = tree match { - case Block(stats, expr) => stats :+ expr - case t => t :: Nil - } - - def listToBlock(trees: List[Tree]): Block = trees match { - case trees @ (init :+ last) => - val pos = trees.map(_.pos).reduceLeft(_ union _) - Block(init, last).setType(last.tpe).setPos(pos) - } - - override def transform(tree: Tree): Block = { - def anfLinearize: Block = { - val trees: List[Tree] = mode match { - case Anf => anf._transformToList(tree) - case Linearizing => linearize._transformToList(tree) - } - listToBlock(trees) - } - tree match { - case _: ValDef | _: DefDef | _: Function | _: ClassDef | _: TypeDef => - atOwner(tree.symbol)(anfLinearize) - case _: ModuleDef => - atOwner(tree.symbol.moduleClass orElse tree.symbol)(anfLinearize) - case _ => - anfLinearize + typingTransform(block)((tree, api) => { + def blockToList(tree: Tree): List[Tree] = tree match { + case Block(stats, expr) => stats :+ expr + case t => t :: Nil } - } - private object linearize { - def transformToList(tree: Tree): List[Tree] = { - mode = Linearizing; blockToList(transform(tree)) + def listToBlock(trees: List[Tree]): Block = trees match { + case trees @ (init :+ last) => + val pos = trees.map(_.pos).reduceLeft(_ union _) + Block(init, last).setType(last.tpe).setPos(pos) } - def transformToBlock(tree: Tree): Block = listToBlock(transformToList(tree)) - - def _transformToList(tree: Tree): List[Tree] = trace(tree) { - val stats :+ expr = anf.transformToList(tree) - def statsExprUnit = - stats :+ expr :+ localTyper.typedPos(expr.pos)(Literal(Constant(()))) - expr match { - case Apply(fun, args) if isAwait(fun) => - val valDef = defineVal(name.await, expr, tree.pos) - stats :+ valDef :+ gen.mkAttributedStableRef(valDef.symbol).setType(tree.tpe).setPos(tree.pos) - - case If(cond, thenp, elsep) => - // if type of if-else is Unit don't introduce assignment, - // but add Unit value to bring it into form expected by async transform - if (expr.tpe =:= definitions.UnitTpe) { + object linearize { + def transformToList(tree: Tree): List[Tree] = { + mode = Linearizing; blockToList(api.recur(tree)) + } + + def transformToBlock(tree: Tree): Block = listToBlock(transformToList(tree)) + + def _transformToList(tree: Tree): List[Tree] = trace(tree) { + val stats :+ expr = anf.transformToList(tree) + def statsExprUnit = + stats :+ expr :+ api.typecheck(atPos(expr.pos)(Literal(Constant(())))) + expr match { + case Apply(fun, args) if isAwait(fun) => + val valDef = defineVal(name.await, expr, tree.pos) + stats :+ valDef :+ gen.mkAttributedStableRef(valDef.symbol).setType(tree.tpe).setPos(tree.pos) + + case If(cond, thenp, elsep) => + // if type of if-else is Unit don't introduce assignment, + // but add Unit value to bring it into form expected by async transform + if (expr.tpe =:= definitions.UnitTpe) { + statsExprUnit + } else { + val varDef = defineVar(name.ifRes, expr.tpe, tree.pos) + def branchWithAssign(orig: Tree) = api.typecheck(atPos(orig.pos) { + def cast(t: Tree) = mkAttributedCastPreservingAnnotations(t, varDef.symbol.tpe) + orig match { + case Block(thenStats, thenExpr) => Block(thenStats, Assign(Ident(varDef.symbol), cast(thenExpr))) + case _ => Assign(Ident(varDef.symbol), cast(orig)) + } + }) + val ifWithAssign = treeCopy.If(tree, cond, branchWithAssign(thenp), branchWithAssign(elsep)).setType(definitions.UnitTpe) + stats :+ varDef :+ ifWithAssign :+ gen.mkAttributedStableRef(varDef.symbol).setType(tree.tpe).setPos(tree.pos) + } + case LabelDef(name, params, rhs) => statsExprUnit - } else { - val varDef = defineVar(name.ifRes, expr.tpe, tree.pos) - def branchWithAssign(orig: Tree) = localTyper.typedPos(orig.pos) { - def cast(t: Tree) = mkAttributedCastPreservingAnnotations(t, varDef.symbol.tpe) - orig match { - case Block(thenStats, thenExpr) => Block(thenStats, Assign(Ident(varDef.symbol), cast(thenExpr))) - case _ => Assign(Ident(varDef.symbol), cast(orig)) + + case Match(scrut, cases) => + // if type of match is Unit don't introduce assignment, + // but add Unit value to bring it into form expected by async transform + if (expr.tpe =:= definitions.UnitTpe) { + statsExprUnit + } + else { + val varDef = defineVar(name.matchRes, expr.tpe, tree.pos) + def typedAssign(lhs: Tree) = + api.typecheck(atPos(lhs.pos)(Assign(Ident(varDef.symbol), mkAttributedCastPreservingAnnotations(lhs, varDef.symbol.tpe)))) + val casesWithAssign = cases map { + case cd@CaseDef(pat, guard, body) => + val newBody = body match { + case b@Block(caseStats, caseExpr) => treeCopy.Block(b, caseStats, typedAssign(caseExpr)).setType(definitions.UnitTpe) + case _ => typedAssign(body) + } + treeCopy.CaseDef(cd, pat, guard, newBody).setType(definitions.UnitTpe) } + val matchWithAssign = treeCopy.Match(tree, scrut, casesWithAssign).setType(definitions.UnitTpe) + require(matchWithAssign.tpe != null, matchWithAssign) + stats :+ varDef :+ matchWithAssign :+ gen.mkAttributedStableRef(varDef.symbol).setPos(tree.pos).setType(tree.tpe) } - val ifWithAssign = treeCopy.If(tree, cond, branchWithAssign(thenp), branchWithAssign(elsep)).setType(definitions.UnitTpe) - stats :+ varDef :+ ifWithAssign :+ gen.mkAttributedStableRef(varDef.symbol).setType(tree.tpe).setPos(tree.pos) - } - case LabelDef(name, params, rhs) => - statsExprUnit + case _ => + stats :+ expr + } + } - case Match(scrut, cases) => - // if type of match is Unit don't introduce assignment, - // but add Unit value to bring it into form expected by async transform - if (expr.tpe =:= definitions.UnitTpe) { - statsExprUnit - } - else { - val varDef = defineVar(name.matchRes, expr.tpe, tree.pos) - def typedAssign(lhs: Tree) = - localTyper.typedPos(lhs.pos)(Assign(Ident(varDef.symbol), mkAttributedCastPreservingAnnotations(lhs, varDef.symbol.tpe))) - val casesWithAssign = cases map { - case cd@CaseDef(pat, guard, body) => - val newBody = body match { - case b@Block(caseStats, caseExpr) => treeCopy.Block(b, caseStats, typedAssign(caseExpr)).setType(definitions.UnitTpe) - case _ => typedAssign(body) - } - treeCopy.CaseDef(cd, pat, guard, newBody).setType(definitions.UnitTpe) - } - val matchWithAssign = treeCopy.Match(tree, scrut, casesWithAssign).setType(definitions.UnitTpe) - require(matchWithAssign.tpe != null, matchWithAssign) - stats :+ varDef :+ matchWithAssign :+ gen.mkAttributedStableRef(varDef.symbol).setPos(tree.pos).setType(tree.tpe) - } - case _ => - stats :+ expr + private def defineVar(prefix: String, tp: Type, pos: Position): ValDef = { + val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(uncheckedBounds(tp)) + ValDef(sym, gen.mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos) } } - private def defineVar(prefix: String, tp: Type, pos: Position): ValDef = { - val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(uncheckedBounds(tp)) - ValDef(sym, gen.mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos) - } - } - - private object trace { - private var indent = -1 - - private def indentString = " " * indent - - def apply[T](args: Any)(t: => T): T = { - def prefix = mode.toString.toLowerCase - indent += 1 - def oneLine(s: Any) = s.toString.replaceAll("""\n""", "\\\\n").take(127) - try { - AsyncUtils.trace(s"${indentString}$prefix(${oneLine(args)})") - val result = t - AsyncUtils.trace(s"${indentString}= ${oneLine(result)}") - result - } finally { - indent -= 1 + object trace { + private var indent = -1 + + private def indentString = " " * indent + + def apply[T](args: Any)(t: => T): T = { + def prefix = mode.toString.toLowerCase + indent += 1 + def oneLine(s: Any) = s.toString.replaceAll("""\n""", "\\\\n").take(127) + try { + AsyncUtils.trace(s"${indentString}$prefix(${oneLine(args)})") + val result = t + AsyncUtils.trace(s"${indentString}= ${oneLine(result)}") + result + } finally { + indent -= 1 + } } } - } - private def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = { - val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe)) - lhs.changeOwner(currentOwner, sym) - ValDef(sym, lhs.changeOwner(currentOwner, sym)).setType(NoType).setPos(pos) - } - - private object anf { - def transformToList(tree: Tree): List[Tree] = { - mode = Anf; blockToList(transform(tree)) + def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = { + val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe)) + lhs.changeOwner(api.currentOwner, sym) + ValDef(sym, lhs.changeOwner(api.currentOwner, sym)).setType(NoType).setPos(pos) } - def _transformToList(tree: Tree): List[Tree] = trace(tree) { - val containsAwait = tree exists isAwait - if (!containsAwait) { - tree match { - case Block(stats, expr) => - // avoids nested block in `while(await(false)) ...`. - // TODO I think `containsAwait` really should return true if the code contains a label jump to an enclosing - // while/doWhile and there is an await *anywhere* inside that construct. - stats :+ expr - case _ => List(tree) - } - } else tree match { - case Select(qual, sel) => - val stats :+ expr = linearize.transformToList(qual) - stats :+ treeCopy.Select(tree, expr, sel) - - case Throw(expr) => - val stats :+ expr1 = linearize.transformToList(expr) - stats :+ treeCopy.Throw(tree, expr1) - - case Typed(expr, tpt) => - val stats :+ expr1 = linearize.transformToList(expr) - stats :+ treeCopy.Typed(tree, expr1, tpt) - - case treeInfo.Applied(fun, targs, argss) if argss.nonEmpty => - // we can assume that no await call appears in a by-name argument position, - // this has already been checked. - val funStats :+ simpleFun = linearize.transformToList(fun) - val (argStatss, argExprss): (List[List[List[Tree]]], List[List[Tree]]) = - mapArgumentss[List[Tree]](fun, argss) { - case Arg(expr, byName, _) if byName /*|| isPure(expr) TODO */ => (Nil, expr) - case Arg(expr, _, argName) => - linearize.transformToList(expr) match { - case stats :+ expr1 => - val valDef = defineVal(argName, expr1, expr1.pos) - require(valDef.tpe != null, valDef) - val stats1 = stats :+ valDef - (stats1, atPos(tree.pos.makeTransparent)(gen.stabilize(gen.mkAttributedIdent(valDef.symbol)))) - } - } + object anf { + def transformToList(tree: Tree): List[Tree] = { + mode = Anf; blockToList(api.recur(tree)) + } - def copyApplied(tree: Tree, depth: Int): Tree = { - tree match { - case TypeApply(_, targs) => treeCopy.TypeApply(tree, simpleFun, targs) - case _ if depth == 0 => simpleFun - case Apply(fun, args) => - val newTypedArgs = map2(args.map(_.pos), argExprss(depth - 1))((pos, arg) => localTyper.typedPos(pos)(arg)) - treeCopy.Apply(tree, copyApplied(fun, depth - 1), newTypedArgs) - } + def _transformToList(tree: Tree): List[Tree] = trace(tree) { + val containsAwait = tree exists isAwait + if (!containsAwait) { + tree match { + case Block(stats, expr) => + // avoids nested block in `while(await(false)) ...`. + // TODO I think `containsAwait` really should return true if the code contains a label jump to an enclosing + // while/doWhile and there is an await *anywhere* inside that construct. + stats :+ expr + case _ => List(tree) } + } else tree match { + case Select(qual, sel) => + val stats :+ expr = linearize.transformToList(qual) + stats :+ treeCopy.Select(tree, expr, sel) + + case Throw(expr) => + val stats :+ expr1 = linearize.transformToList(expr) + stats :+ treeCopy.Throw(tree, expr1) + + case Typed(expr, tpt) => + val stats :+ expr1 = linearize.transformToList(expr) + stats :+ treeCopy.Typed(tree, expr1, tpt) + + case treeInfo.Applied(fun, targs, argss) if argss.nonEmpty => + // we can assume that no await call appears in a by-name argument position, + // this has already been checked. + val funStats :+ simpleFun = linearize.transformToList(fun) + val (argStatss, argExprss): (List[List[List[Tree]]], List[List[Tree]]) = + mapArgumentss[List[Tree]](fun, argss) { + case Arg(expr, byName, _) if byName /*|| isPure(expr) TODO */ => (Nil, expr) + case Arg(expr, _, argName) => + linearize.transformToList(expr) match { + case stats :+ expr1 => + val valDef = defineVal(argName, expr1, expr1.pos) + require(valDef.tpe != null, valDef) + val stats1 = stats :+ valDef + (stats1, atPos(tree.pos.makeTransparent)(gen.stabilize(gen.mkAttributedIdent(valDef.symbol)))) + } + } + + def copyApplied(tree: Tree, depth: Int): Tree = { + tree match { + case TypeApply(_, targs) => treeCopy.TypeApply(tree, simpleFun, targs) + case _ if depth == 0 => simpleFun + case Apply(fun, args) => + val newTypedArgs = map2(args.map(_.pos), argExprss(depth - 1))((pos, arg) => api.typecheck(atPos(pos)(arg))) + treeCopy.Apply(tree, copyApplied(fun, depth - 1), newTypedArgs) + } + } - /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _) - * has depth 3. Continues through type applications (without counting them.) - */ - def applyDepth: Int = { - def loop(tree: Tree): Int = tree match { - case Apply(fn, _) => 1 + loop(fn) - case TypeApply(fn, _) => loop(fn) - case AppliedTypeTree(fn, _) => loop(fn) - case _ => 0 + /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _) + * has depth 3. Continues through type applications (without counting them.) + */ + def applyDepth: Int = { + def loop(tree: Tree): Int = tree match { + case Apply(fn, _) => 1 + loop(fn) + case TypeApply(fn, _) => loop(fn) + case AppliedTypeTree(fn, _) => loop(fn) + case _ => 0 + } + loop(tree) } - loop(tree) - } - val typedNewApply = copyApplied(tree, applyDepth) - - funStats ++ argStatss.flatten.flatten :+ typedNewApply - - case Block(stats, expr) => - (stats :+ expr).flatMap(linearize.transformToList) - - case ValDef(mods, name, tpt, rhs) => - if (rhs exists isAwait) { - val stats :+ expr = atOwner(currOwner.owner)(linearize.transformToList(rhs)) - stats.foreach(_.changeOwner(currOwner, currOwner.owner)) - stats :+ treeCopy.ValDef(tree, mods, name, tpt, expr) - } else List(tree) - - case Assign(lhs, rhs) => - val stats :+ expr = linearize.transformToList(rhs) - stats :+ treeCopy.Assign(tree, lhs, expr) - - case If(cond, thenp, elsep) => - val condStats :+ condExpr = linearize.transformToList(cond) - val thenBlock = linearize.transformToBlock(thenp) - val elseBlock = linearize.transformToBlock(elsep) - condStats :+ treeCopy.If(tree, condExpr, thenBlock, elseBlock) - - case Match(scrut, cases) => - val scrutStats :+ scrutExpr = linearize.transformToList(scrut) - val caseDefs = cases map { - case CaseDef(pat, guard, body) => - // extract local variables for all names bound in `pat`, and rewrite `body` - // to refer to these. - // TODO we can move this into ExprBuilder once we get rid of `AsyncDefinitionUseAnalyzer`. - val block = linearize.transformToBlock(body) - val (valDefs, mappings) = (pat collect { - case b@Bind(name, _) => - val vd = defineVal(name.toTermName + AnfTransform.this.name.bindSuffix, gen.mkAttributedStableRef(b.symbol).setPos(b.pos), b.pos) - (vd, (b.symbol, vd.symbol)) - }).unzip - val (from, to) = mappings.unzip - val b@Block(stats1, expr1) = block.substituteSymbols(from, to).asInstanceOf[Block] - val newBlock = treeCopy.Block(b, valDefs ++ stats1, expr1) - treeCopy.CaseDef(tree, pat, guard, newBlock) - } - scrutStats :+ treeCopy.Match(tree, scrutExpr, caseDefs) + val typedNewApply = copyApplied(tree, applyDepth) + + funStats ++ argStatss.flatten.flatten :+ typedNewApply + + case Block(stats, expr) => + (stats :+ expr).flatMap(linearize.transformToList) + + case ValDef(mods, name, tpt, rhs) => + if (rhs exists isAwait) { + val stats :+ expr = api.atOwner(api.currentOwner.owner)(linearize.transformToList(rhs)) + stats.foreach(_.changeOwner(api.currentOwner, api.currentOwner.owner)) + stats :+ treeCopy.ValDef(tree, mods, name, tpt, expr) + } else List(tree) + + case Assign(lhs, rhs) => + val stats :+ expr = linearize.transformToList(rhs) + stats :+ treeCopy.Assign(tree, lhs, expr) + + case If(cond, thenp, elsep) => + val condStats :+ condExpr = linearize.transformToList(cond) + val thenBlock = linearize.transformToBlock(thenp) + val elseBlock = linearize.transformToBlock(elsep) + condStats :+ treeCopy.If(tree, condExpr, thenBlock, elseBlock) + + case Match(scrut, cases) => + val scrutStats :+ scrutExpr = linearize.transformToList(scrut) + val caseDefs = cases map { + case CaseDef(pat, guard, body) => + // extract local variables for all names bound in `pat`, and rewrite `body` + // to refer to these. + // TODO we can move this into ExprBuilder once we get rid of `AsyncDefinitionUseAnalyzer`. + val block = linearize.transformToBlock(body) + val (valDefs, mappings) = (pat collect { + case b@Bind(name, _) => + val vd = defineVal(name.toTermName + AnfTransform.this.name.bindSuffix, gen.mkAttributedStableRef(b.symbol).setPos(b.pos), b.pos) + (vd, (b.symbol, vd.symbol)) + }).unzip + val (from, to) = mappings.unzip + val b@Block(stats1, expr1) = block.substituteSymbols(from, to).asInstanceOf[Block] + val newBlock = treeCopy.Block(b, valDefs ++ stats1, expr1) + treeCopy.CaseDef(tree, pat, guard, newBlock) + } + scrutStats :+ treeCopy.Match(tree, scrutExpr, caseDefs) + + case LabelDef(name, params, rhs) => + List(LabelDef(name, params, Block(linearize.transformToList(rhs), Literal(Constant(())))).setSymbol(tree.symbol)) - case LabelDef(name, params, rhs) => - List(LabelDef(name, params, Block(linearize.transformToList(rhs), Literal(Constant(())))).setSymbol(tree.symbol)) + case TypeApply(fun, targs) => + val funStats :+ simpleFun = linearize.transformToList(fun) + funStats :+ treeCopy.TypeApply(tree, simpleFun, targs) - case TypeApply(fun, targs) => - val funStats :+ simpleFun = linearize.transformToList(fun) - funStats :+ treeCopy.TypeApply(tree, simpleFun, targs) + case _ => + List(tree) + } + } + } - case _ => - List(tree) + def anfLinearize(tree: Tree): Block = { + val trees: List[Tree] = mode match { + case Anf => anf._transformToList(tree) + case Linearizing => linearize._transformToList(tree) } + listToBlock(trees) + } + + tree match { + case _: ValDef | _: DefDef | _: Function | _: ClassDef | _: TypeDef => + api.atOwner(tree.symbol)(anfLinearize(tree)) + case _: ModuleDef => + api.atOwner(tree.symbol.moduleClass orElse tree.symbol)(anfLinearize(tree)) + case _ => + anfLinearize(tree) } - } + }).asInstanceOf[Block] } } From cc47ec1102db0a0e09d4b321226f5fdaa8e6c455 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:51:51 +0100 Subject: [PATCH 25/27] callSiteTyper and TypingTransformers are gone --- src/main/scala/scala/async/internal/AsyncMacro.scala | 5 +---- src/main/scala/scala/async/internal/TransformUtils.scala | 9 --------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncMacro.scala b/src/main/scala/scala/async/internal/AsyncMacro.scala index 7215ce92..4af69bc1 100644 --- a/src/main/scala/scala/async/internal/AsyncMacro.scala +++ b/src/main/scala/scala/async/internal/AsyncMacro.scala @@ -10,7 +10,6 @@ object AsyncMacro { new AsyncMacro { self => val c: scala.reflect.macros.Context { val universe: global.type } = c0.asInstanceOf[scala.reflect.macros.Context { val universe: global.type }] val global: powerContext.universe.type = powerContext.universe - val callSiteTyper: global.analyzer.Typer = powerContext.callsiteTyper val macroApplication: global.Tree = c0.macroApplication.asInstanceOf[global.Tree] // This member is required by `AsyncTransform`: val asyncBase: AsyncBase = base @@ -22,13 +21,11 @@ object AsyncMacro { } private[async] trait AsyncMacro - extends TypingTransformers - with AnfTransform with TransformUtils with Lifter + extends AnfTransform with TransformUtils with Lifter with ExprBuilder with AsyncTransform with AsyncAnalysis with LiveVariables { val c: scala.reflect.macros.Context { val universe: global.type } val global: Global - val callSiteTyper: global.analyzer.Typer val macroApplication: global.Tree lazy val macroPos = macroApplication.pos.makeTransparent diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 18e994fc..03046a08 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -206,15 +206,6 @@ private[async] trait TransformUtils { } } - abstract class MacroTypingTransformer extends TypingTransformer(callSiteTyper.context.unit) { - currentOwner = enclosingOwner - curTree = EmptyTree - - def currOwner: Symbol = currentOwner - - localTyper = global.analyzer.newTyper(callSiteTyper.context.make(unit = callSiteTyper.context.unit)) - } - def transformAt(tree: Tree)(f: PartialFunction[Tree, (TypingTransformApi => Tree)]) = { typingTransform(tree)((tree, api) => { if (f.isDefinedAt(tree)) f(tree)(api) From ac7ba71649217de837f1cad40d7e9b1fc2a07c11 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 00:54:38 +0100 Subject: [PATCH 26/27] AsyncMacro.macroApplication is gone --- src/main/scala/scala/async/internal/AsyncMacro.scala | 6 ++---- src/main/scala/scala/async/internal/AsyncTransform.scala | 2 +- src/main/scala/scala/async/internal/TransformUtils.scala | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/scala/scala/async/internal/AsyncMacro.scala b/src/main/scala/scala/async/internal/AsyncMacro.scala index 4af69bc1..30aa1dd1 100644 --- a/src/main/scala/scala/async/internal/AsyncMacro.scala +++ b/src/main/scala/scala/async/internal/AsyncMacro.scala @@ -10,7 +10,6 @@ object AsyncMacro { new AsyncMacro { self => val c: scala.reflect.macros.Context { val universe: global.type } = c0.asInstanceOf[scala.reflect.macros.Context { val universe: global.type }] val global: powerContext.universe.type = powerContext.universe - val macroApplication: global.Tree = c0.macroApplication.asInstanceOf[global.Tree] // This member is required by `AsyncTransform`: val asyncBase: AsyncBase = base // These members are required by `ExprBuilder`: @@ -26,8 +25,7 @@ private[async] trait AsyncMacro val c: scala.reflect.macros.Context { val universe: global.type } val global: Global - val macroApplication: global.Tree - lazy val macroPos = macroApplication.pos.makeTransparent - def atMacroPos(t: global.Tree) = global.atPos(macroPos)(t) + lazy val macroPos = c.macroApplication.pos.makeTransparent + def atMacroPos(t: global.Tree) = c.universe.atPos(macroPos)(t) } diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index 8b6abe13..f66644f8 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -123,7 +123,7 @@ trait AsyncTransform { } AsyncUtils.vprintln(s"In file '$location':") - AsyncUtils.vprintln(s"${macroApplication}") + AsyncUtils.vprintln(s"${c.macroApplication}") AsyncUtils.vprintln(s"ANF transform expands to:\n $anfTree") states foreach (s => AsyncUtils.vprintln(s)) } diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 03046a08..c44b2c8e 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -83,7 +83,7 @@ private[async] trait TransformUtils { } val NonFatalClass = rootMirror.staticModule("scala.util.control.NonFatal") - val Async_await = asyncBase.awaitMethod(c.universe)(macroApplication.symbol).ensuring(_ != NoSymbol) + val Async_await = asyncBase.awaitMethod(c.universe)(c.macroApplication.symbol).ensuring(_ != NoSymbol) } def isSafeToInline(tree: Tree) = { From bc51a19ab4c7fccfa64554dce5098481aec8cdac Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 15 Feb 2014 01:29:03 +0100 Subject: [PATCH 27/27] AsyncMacro.global is gone --- .../scala/async/internal/AnfTransform.scala | 16 +++---- .../scala/async/internal/AsyncAnalysis.scala | 2 +- .../scala/async/internal/AsyncBase.scala | 5 +- .../scala/async/internal/AsyncMacro.scala | 18 +++---- .../scala/async/internal/AsyncTransform.scala | 14 +++--- .../scala/async/internal/ExprBuilder.scala | 1 + .../scala/scala/async/internal/Lifter.scala | 24 +++++----- .../scala/async/internal/LiveVariables.scala | 2 +- .../scala/async/internal/TransformUtils.scala | 47 +++++++++++++++---- 9 files changed, 76 insertions(+), 53 deletions(-) diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index dc526832..0e58fa7e 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -5,13 +5,13 @@ package scala.async.internal -import scala.tools.nsc.Global import scala.Predef._ +import scala.reflect.internal.util.Collections.map2 private[async] trait AnfTransform { self: AsyncMacro => - import c.universe.{gen => _, _} + import c.universe._ import Flag._ import c.internal._ import decorators._ @@ -61,7 +61,7 @@ private[async] trait AnfTransform { } else { val varDef = defineVar(name.ifRes, expr.tpe, tree.pos) def branchWithAssign(orig: Tree) = api.typecheck(atPos(orig.pos) { - def cast(t: Tree) = mkAttributedCastPreservingAnnotations(t, varDef.symbol.tpe) + def cast(t: Tree) = mkAttributedCastPreservingAnnotations(t, tpe(varDef.symbol)) orig match { case Block(thenStats, thenExpr) => Block(thenStats, Assign(Ident(varDef.symbol), cast(thenExpr))) case _ => Assign(Ident(varDef.symbol), cast(orig)) @@ -82,7 +82,7 @@ private[async] trait AnfTransform { else { val varDef = defineVar(name.matchRes, expr.tpe, tree.pos) def typedAssign(lhs: Tree) = - api.typecheck(atPos(lhs.pos)(Assign(Ident(varDef.symbol), mkAttributedCastPreservingAnnotations(lhs, varDef.symbol.tpe)))) + api.typecheck(atPos(lhs.pos)(Assign(Ident(varDef.symbol), mkAttributedCastPreservingAnnotations(lhs, tpe(varDef.symbol))))) val casesWithAssign = cases map { case cd@CaseDef(pat, guard, body) => val newBody = body match { @@ -102,7 +102,7 @@ private[async] trait AnfTransform { private def defineVar(prefix: String, tp: Type, pos: Position): ValDef = { val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(uncheckedBounds(tp)) - ValDef(sym, gen.mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos) + valDef(sym, gen.mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos) } } @@ -129,7 +129,7 @@ private[async] trait AnfTransform { def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = { val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe)) lhs.changeOwner(api.currentOwner, sym) - ValDef(sym, lhs.changeOwner(api.currentOwner, sym)).setType(NoType).setPos(pos) + valDef(sym, lhs.changeOwner(api.currentOwner, sym)).setType(NoType).setPos(pos) } object anf { @@ -161,7 +161,7 @@ private[async] trait AnfTransform { val stats :+ expr1 = linearize.transformToList(expr) stats :+ treeCopy.Typed(tree, expr1, tpt) - case treeInfo.Applied(fun, targs, argss) if argss.nonEmpty => + case q"$fun[..$targs](...$argss)" if argss.nonEmpty => // we can assume that no await call appears in a by-name argument position, // this has already been checked. val funStats :+ simpleFun = linearize.transformToList(fun) @@ -271,7 +271,7 @@ private[async] trait AnfTransform { case _: ValDef | _: DefDef | _: Function | _: ClassDef | _: TypeDef => api.atOwner(tree.symbol)(anfLinearize(tree)) case _: ModuleDef => - api.atOwner(tree.symbol.moduleClass orElse tree.symbol)(anfLinearize(tree)) + api.atOwner(tree.symbol.asModule.moduleClass orElse tree.symbol)(anfLinearize(tree)) case _ => anfLinearize(tree) } diff --git a/src/main/scala/scala/async/internal/AsyncAnalysis.scala b/src/main/scala/scala/async/internal/AsyncAnalysis.scala index 4339653a..ffbc04db 100644 --- a/src/main/scala/scala/async/internal/AsyncAnalysis.scala +++ b/src/main/scala/scala/async/internal/AsyncAnalysis.scala @@ -28,7 +28,7 @@ trait AsyncAnalysis { var hasUnsupportedAwaits = false override def nestedClass(classDef: ClassDef) { - val kind = if (classDef.symbol.isTrait) "trait" else "class" + val kind = if (classDef.symbol.asClass.isTrait) "trait" else "class" reportUnsupportedAwait(classDef, s"nested ${kind}") } diff --git a/src/main/scala/scala/async/internal/AsyncBase.scala b/src/main/scala/scala/async/internal/AsyncBase.scala index 3d4810b8..7464c42d 100644 --- a/src/main/scala/scala/async/internal/AsyncBase.scala +++ b/src/main/scala/scala/async/internal/AsyncBase.scala @@ -45,10 +45,7 @@ abstract class AsyncBase { import c.universe._, c.internal._, decorators._ val asyncMacro = AsyncMacro(c, self) - val code = asyncMacro.asyncTransform[T]( - body.tree.asInstanceOf[asyncMacro.global.Tree], - execContext.tree.asInstanceOf[asyncMacro.global.Tree] - )(implicitly[c.WeakTypeTag[T]].asInstanceOf[asyncMacro.global.WeakTypeTag[T]]).asInstanceOf[Tree] + val code = asyncMacro.asyncTransform[T](body.tree, execContext.tree)(c.weakTypeTag[T]) AsyncUtils.vprintln(s"async state machine transform expands to:\n ${code}") // Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges diff --git a/src/main/scala/scala/async/internal/AsyncMacro.scala b/src/main/scala/scala/async/internal/AsyncMacro.scala index 30aa1dd1..e969f9bc 100644 --- a/src/main/scala/scala/async/internal/AsyncMacro.scala +++ b/src/main/scala/scala/async/internal/AsyncMacro.scala @@ -1,19 +1,14 @@ package scala.async.internal -import scala.tools.nsc.Global -import scala.tools.nsc.transform.TypingTransformers - object AsyncMacro { - def apply(c0: reflect.macros.Context, base: AsyncBase): AsyncMacro = { + def apply(c0: reflect.macros.Context, base: AsyncBase): AsyncMacro { val c: c0.type } = { import language.reflectiveCalls - val powerContext = c0.asInstanceOf[c0.type { val universe: Global; val callsiteTyper: universe.analyzer.Typer }] new AsyncMacro { self => - val c: scala.reflect.macros.Context { val universe: global.type } = c0.asInstanceOf[scala.reflect.macros.Context { val universe: global.type }] - val global: powerContext.universe.type = powerContext.universe + val c: c0.type = c0 // This member is required by `AsyncTransform`: - val asyncBase: AsyncBase = base + val asyncBase: AsyncBase = base // These members are required by `ExprBuilder`: - val futureSystem: FutureSystem = base.futureSystem + val futureSystem: FutureSystem = base.futureSystem val futureSystemOps: futureSystem.Ops {val c: self.c.type} = futureSystem.mkOps(c) } } @@ -23,9 +18,8 @@ private[async] trait AsyncMacro extends AnfTransform with TransformUtils with Lifter with ExprBuilder with AsyncTransform with AsyncAnalysis with LiveVariables { - val c: scala.reflect.macros.Context { val universe: global.type } - val global: Global + val c: scala.reflect.macros.Context lazy val macroPos = c.macroApplication.pos.makeTransparent - def atMacroPos(t: global.Tree) = c.universe.atPos(macroPos)(t) + def atMacroPos(t: c.Tree) = c.universe.atPos(macroPos)(t) } diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index f66644f8..cf9dd1cc 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -3,7 +3,7 @@ package scala.async.internal trait AsyncTransform { self: AsyncMacro => - import c.universe.{gen => _, _} + import c.universe._ import c.internal._ import decorators._ @@ -15,7 +15,7 @@ trait AsyncTransform { // We annotate the type of the whole expression as `T @uncheckedBounds` so as not to introduce // warnings about non-conformant LUBs. See SI-7694 // This implicit propagates the annotated type in the type tag. - implicit val uncheckedBoundsResultTag: WeakTypeTag[T] = WeakTypeTag[T](rootMirror, FixedMirrorTypeCreator(rootMirror, uncheckedBounds(resultType.tpe))) + implicit val uncheckedBoundsResultTag: WeakTypeTag[T] = c.WeakTypeTag[T](uncheckedBounds(resultType.tpe)) reportUnsupportedAwaits(body) @@ -82,7 +82,7 @@ trait AsyncTransform { List( asyncBase.nullOut(c.universe)(c.Expr[String](Literal(Constant(fieldSym.name.toString))), c.Expr[Any](Ident(fieldSym))).tree ), - Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), gen.mkZero(fieldSym.info)) + Assign(gen.mkAttributedStableRef(thisType(fieldSym.owner), fieldSym), gen.mkZero(fieldSym.info)) ) } val asyncState = asyncBlock.asyncStates.find(_.state == state).get @@ -143,9 +143,9 @@ trait AsyncTransform { liftedSyms.foreach { sym => if (sym != null) { - sym.owner = stateMachineClass + sym.setOwner(stateMachineClass) if (sym.isModule) - sym.moduleClass.owner = stateMachineClass + sym.asModule.moduleClass.setOwner(stateMachineClass) } } // Replace the ValDefs in the splicee with Assigns to the corresponding lifted @@ -158,7 +158,7 @@ trait AsyncTransform { case ValDef(_, _, _, rhs) if liftedSyms(tree.symbol) => api.atOwner(api.currentOwner) { val fieldSym = tree.symbol - val set = Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), api.recur(rhs)) + val set = Assign(gen.mkAttributedStableRef(thisType(fieldSym.owner.asClass), fieldSym), api.recur(rhs)) set.changeOwner(tree.symbol, api.currentOwner) api.typecheck(atPos(tree.pos)(set)) } @@ -167,7 +167,7 @@ trait AsyncTransform { case Ident(name) if liftedSyms(tree.symbol) => val fieldSym = tree.symbol atPos(tree.pos) { - gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym).setType(tree.tpe) + gen.mkAttributedStableRef(thisType(fieldSym.owner.asClass), fieldSym).setType(tree.tpe) } case _ => api.default(tree) diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index 893556f1..2e313475 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -15,6 +15,7 @@ trait ExprBuilder { import c.universe._ import defn._ + import c.internal._ val futureSystem: FutureSystem val futureSystemOps: futureSystem.Ops { val c: builder.c.type } diff --git a/src/main/scala/scala/async/internal/Lifter.scala b/src/main/scala/scala/async/internal/Lifter.scala index 024b0364..bf7bdbd5 100644 --- a/src/main/scala/scala/async/internal/Lifter.scala +++ b/src/main/scala/scala/async/internal/Lifter.scala @@ -4,6 +4,8 @@ trait Lifter { self: AsyncMacro => import c.universe._ import Flag._ + import c.internal._ + import decorators._ /** * Identify which DefTrees are used (including transitively) which are declared @@ -88,7 +90,7 @@ trait Lifter { // Only mark transitive references of defs, modules and classes. The RHS of lifted vals/vars // stays in its original location, so things that it refers to need not be lifted. - if (!(sym.isVal || sym.isVar)) + if (!(sym.isTerm && (sym.asTerm.isVal || sym.asTerm.isVar))) defSymToReferenced(sym).foreach(sym2 => markForLift(sym2)) } } @@ -111,35 +113,35 @@ trait Lifter { val treeLifted = t match { case vd@ValDef(_, _, tpt, rhs) => sym.setFlag(MUTABLE | STABLE | PRIVATE | LOCAL) - sym.name = name.fresh(sym.name.toTermName) - sym.modifyInfo(_.deconst) + sym.setName(name.fresh(sym.name.toTermName)) + sym.setInfo(deconst(sym.info)) val zeroRhs = atPos(t.pos)(gen.mkZero(vd.symbol.info)) - treeCopy.ValDef(vd, Modifiers(sym.flags), sym.name, TypeTree(sym.tpe).setPos(t.pos), zeroRhs) + treeCopy.ValDef(vd, Modifiers(sym.flags), sym.name, TypeTree(tpe(sym)).setPos(t.pos), zeroRhs) case dd@DefDef(_, _, tparams, vparamss, tpt, rhs) => - sym.name = this.name.fresh(sym.name.toTermName) + sym.setName(this.name.fresh(sym.name.toTermName)) sym.setFlag(PRIVATE | LOCAL) // Was `DefDef(sym, rhs)`, but this ran afoul of `ToughTypeSpec.nestedMethodWithInconsistencyTreeAndInfoParamSymbols` // due to the handling of type parameter skolems in `thisMethodType` in `Namers` treeCopy.DefDef(dd, Modifiers(sym.flags), sym.name, tparams, vparamss, tpt, rhs) case cd@ClassDef(_, _, tparams, impl) => - sym.name = newTypeName(name.fresh(sym.name.toString).toString) + sym.setName(newTypeName(name.fresh(sym.name.toString).toString)) companionship.companionOf(cd.symbol) match { case NoSymbol => case moduleSymbol => - moduleSymbol.name = sym.name.toTermName - moduleSymbol.moduleClass.name = moduleSymbol.name.toTypeName + moduleSymbol.setName(sym.name.toTermName) + moduleSymbol.asModule.moduleClass.setName(moduleSymbol.name.toTypeName) } treeCopy.ClassDef(cd, Modifiers(sym.flags), sym.name, tparams, impl) case md@ModuleDef(_, _, impl) => companionship.companionOf(md.symbol) match { case NoSymbol => - sym.name = name.fresh(sym.name.toTermName) - sym.moduleClass.name = sym.name.toTypeName + sym.setName(name.fresh(sym.name.toTermName)) + sym.asModule.moduleClass.setName(sym.name.toTypeName) case classSymbol => // will be renamed by `case ClassDef` above. } treeCopy.ModuleDef(md, Modifiers(sym.flags), sym.name, impl) case td@TypeDef(_, _, tparams, rhs) => - sym.name = newTypeName(name.fresh(sym.name.toString).toString) + sym.setName(newTypeName(name.fresh(sym.name.toString).toString)) treeCopy.TypeDef(td, Modifiers(sym.flags), sym.name, tparams, rhs) } atPos(t.pos)(treeLifted) diff --git a/src/main/scala/scala/async/internal/LiveVariables.scala b/src/main/scala/scala/async/internal/LiveVariables.scala index 5a7a3e40..6c67e996 100644 --- a/src/main/scala/scala/async/internal/LiveVariables.scala +++ b/src/main/scala/scala/async/internal/LiveVariables.scala @@ -55,7 +55,7 @@ trait LiveVariables { // determine which fields should be live also at the end (will not be nulled out) val noNull: Set[Symbol] = liftedSyms.filter { sym => - sym.tpe.typeSymbol.isPrimitiveValueClass || liftables.exists { tree => + tpe(sym).typeSymbol.asClass.isPrimitive || liftables.exists { tree => !liftedSyms.contains(tree.symbol) && tree.exists(_.symbol == sym) } } diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index c44b2c8e..5d0a96fd 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -5,6 +5,7 @@ package scala.async.internal import scala.reflect.macros.Context import reflect.ClassTag +import scala.collection.immutable.ListMap /** * Utilities used in both `ExprBuilder` and `AnfTransform`. @@ -12,8 +13,9 @@ import reflect.ClassTag private[async] trait TransformUtils { self: AsyncMacro => - import c.universe.{gen => _, _} + import c.universe._ import c.internal._ + import decorators._ object name { val resume = newTermName("resume") @@ -51,7 +53,7 @@ private[async] trait TransformUtils { if (Boolean_ShortCircuits contains fun.symbol) (i, j) => true else { val paramss = fun.tpe.paramss - val byNamess = paramss.map(_.map(_.isByNameParam)) + val byNamess = paramss.map(_.map(_.asTerm.isByNameParam)) (i, j) => util.Try(byNamess(i)(j)).getOrElse(false) } } @@ -86,10 +88,6 @@ private[async] trait TransformUtils { val Async_await = asyncBase.awaitMethod(c.universe)(c.macroApplication.symbol).ensuring(_ != NoSymbol) } - def isSafeToInline(tree: Tree) = { - treeInfo.isExprSafeToInline(tree) - } - // `while(await(x))` ... or `do { await(x); ... } while(...)` contain an `If` that loops; // we must break that `If` into states so that it convert the label jump into a state machine // transition @@ -192,7 +190,7 @@ private[async] trait TransformUtils { case dd: DefDef => nestedMethod(dd) case fun: Function => function(fun) case m@Match(EmptyTree, _) => patMatFunction(m) // Pattern matching anonymous function under -Xoldpatmat of after `restorePatternMatchingFunctions` - case treeInfo.Applied(fun, targs, argss) if argss.nonEmpty => + case q"$fun[..$targs](...$argss)" if argss.nonEmpty => val isInByName = isByName(fun) for ((args, i) <- argss.zipWithIndex) { for ((arg, j) <- args.zipWithIndex) { @@ -219,11 +217,42 @@ private[async] trait TransformUtils { // Attributed version of `TreeGen#mkCastPreservingAnnotations` def mkAttributedCastPreservingAnnotations(tree: Tree, tp: Type): Tree = { atPos(tree.pos) { - val casted = c.typecheck(gen.mkCast(tree, uncheckedBounds(tp.withoutAnnotations).dealias)) + val casted = c.typecheck(gen.mkCast(tree, uncheckedBounds(withoutAnnotations(tp)).dealias)) Typed(casted, TypeTree(tp)).setType(tp) } } + def deconst(tp: Type): Type = tp match { + case AnnotatedType(anns, underlying) => annotatedType(anns, deconst(underlying)) + case ExistentialType(quants, underlying) => existentialType(quants, deconst(underlying)) + case ConstantType(value) => deconst(value.tpe) + case _ => tp + } + + def withAnnotation(tp: Type, ann: Annotation): Type = withAnnotations(tp, List(ann)) + + def withAnnotations(tp: Type, anns: List[Annotation]): Type = tp match { + case AnnotatedType(existingAnns, underlying) => annotatedType(anns ::: existingAnns, underlying) + case ExistentialType(quants, underlying) => existentialType(quants, withAnnotations(underlying, anns)) + case _ => annotatedType(anns, tp) + } + + def withoutAnnotations(tp: Type): Type = tp match { + case AnnotatedType(anns, underlying) => withoutAnnotations(underlying) + case ExistentialType(quants, underlying) => existentialType(quants, withoutAnnotations(underlying)) + case _ => tp + } + + def tpe(sym: Symbol): Type = { + if (sym.isType) sym.asType.toType + else sym.info + } + + def thisType(sym: Symbol): Type = { + if (sym.isClass) sym.asClass.thisPrefix + else NoPrefix + } + // ===================================== // Copy/Pasted from Scala 2.10.3. See SI-7694. private lazy val UncheckedBoundsClass = { @@ -232,7 +261,7 @@ private[async] trait TransformUtils { } final def uncheckedBounds(tp: Type): Type = { if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp - else tp.withAnnotation(AnnotationInfo marker UncheckedBoundsClass.tpe) + else withAnnotation(tp, Annotation(UncheckedBoundsClass.asType.toType, Nil, ListMap())) } // ===================================== }